/* webim javascript SDK
 * VER 1.6.0
 */

/* webim API definitions
 */
var webim = { // namespace object webim

	/* function init
	 *   sdk登录
	 * params:
	 *   loginInfo		- Object, 登录身份相关参数集合，详见下面
	 *   {
	 *     sdkAppID		- String, 用户标识接入SDK的应用ID，必填
         *     accountType	- int, 账号类型，必填
	 *     identifier	- String, 用户帐号,必须是字符串类型，必填
         *     identifierNick	- String, 用户昵称，选填
	 *     userSig		- String, 鉴权Token，必须是字符串类型，必填
	 *   }
	 *   listeners		- Object, 事件回调函数集合, 详见下面
	 *   {
	 *     onConnNotify - function(connInfo), 用于收到连接状态相关通知的回调函数,目前未使用
	 *     jsonpCallback -function(rspData),//IE9(含)以下浏览器用到的jsonp回调函数
	 *     onMsgNotify	- function(newMsgList), 用于收到消息通知的回调函数, 
         *      newMsgList为新消息数组，格式为[Msg对象]
	 *      使用方有两种处理回调: 1)处理newMsgList中的增量消息,2)直接访问webim.MsgStore获取最新的消息
	 *     onGroupInfoChangeNotify	- function(groupInfo), 用于监听群组资料变更的回调函数, 
         *          groupInfo为新的群组资料信息
	 *     onGroupSystemNotifys	- Object, 用于监听（多终端同步）群系统消息的回调函数对象
	 *   			 	  
	 *   }
	 *   options		- Object, 其它选项, 目前未使用
	 * return:
	 *   (无)
	 */
	login: function(loginInfo, listeners, options) {},

	/* function syncMsgs
	 *   拉取最新C2C消息
	 *   一般不需要使用方直接调用, SDK底层会自动同步最新消息并通知使用方, 一种有用的调用场景是用户手动触发刷新消息
	 * params:
	 *   cbOk	- function(msgList)类型, 当同步消息成功时的回调函数, msgList为新消息数组，格式为[Msg对象],
	 *   		  如果此参数为null或undefined则同步消息成功后会像自动同步那样回调cbNotify
	 *   cbErr	- function(err)类型, 当同步消息失败时的回调函数, err为错误对象
	 * return:
	 *   (无)
	 */
	syncMsgs: function(cbOk, cbErr) {},

        
	/* function getC2CHistoryMsgs
	 * 拉取C2C漫游消息
	 * params:
	 *   options	- 请求参数
	 *   cbOk	- function(msgList)类型, 成功时的回调函数, msgList为消息数组，格式为[Msg对象],
	 *   cbErr	- function(err)类型, 失败时回调函数, err为错误对象
	 * return:
	 *   (无)
	 */
	getC2CHistoryMsgs: function(options,cbOk, cbErr) {},
        
	/* function syncGroupMsgs
	 * 拉取群漫游消息
	 * params:
	 *   options	- 请求参数
	 *   cbOk	- function(msgList)类型, 成功时的回调函数, msgList为消息数组，格式为[Msg对象],
	 *   cbErr	- function(err)类型, 失败时回调函数, err为错误对象
	 * return:
	 *   (无)
	 */
	syncGroupMsgs: function(options,cbOk, cbErr) {},

	/* function sendMsg
	 *   发送一条消息
	 * params:
	 *   msg	- webim.Msg类型, 要发送的消息对象
	 *   cbOk	- function()类型, 当发送消息成功时的回调函数
	 *   cbErr	- function(err)类型, 当发送消息失败时的回调函数, err为错误对象
	 * return:
	 *   (无)
	 */
	sendMsg: function(msg, cbOk, cbErr) {},
        
	/* function logout
	 *   sdk登出
	 * params:
	 *   cbOk	- function()类型, 成功时回调函数
	 *   cbErr	- function(err)类型, 失败时回调函数, err为错误对象
	 * return:
	 *   (无)
	 */
	logout: function(cbOk, cbErr) {},
        
	/* function setAutoRead
	 * 设置会话自动已读上报标志
	 * params:
	 *   selSess	- webim.Session类型, 当前会话
	 *   isOn	- boolean, 将selSess的自动已读消息标志改为isOn，同时是否上报当前会话已读消息
	 *   isResetAll	- boolean，是否重置所有会话的自动已读标志
	 * return:
	 *   (无)
	 */
	setAutoRead: function(selSess, isOn, isResetAll) {},
        
	/* function getProfilePortrait
	 *   拉取资料（搜索用户）
	 * params:
	 *   cbOk	- function()类型, 成功时回调函数
	 *   cbErr	- function(err)类型, 失败时回调函数, err为错误对象
	 * return:
	 *   (无)
	 */
	getProfilePortrait: function(options,cbOk, cbErr) {},
        
	/* function setProfilePortrait
	 *   设置个人资料
	 * params:
	 *   cbOk	- function()类型, 成功时回调函数
	 *   cbErr	- function(err)类型, 失败时回调函数, err为错误对象
	 * return:
	 *   (无)
	 */
	setProfilePortrait: function(options,cbOk, cbErr) {},
        
	/* function applyAddFriend 
	 *   申请添加好友
	 * params:
	 *   cbOk	- function()类型, 成功时回调函数
	 *   cbErr	- function(err)类型, 失败时回调函数, err为错误对象
	 * return:
	 *   (无)
	 */
	applyAddFriend: function(options,cbOk, cbErr) {},
        
	/* function getPendency 
	 *   拉取好友申请
	 * params:
	 *   cbOk	- function()类型, 成功时回调函数
	 *   cbErr	- function(err)类型, 失败时回调函数, err为错误对象
	 * return:
	 *   (无)
	 */
	getPendency: function(options,cbOk, cbErr) {},
        
	/* function deletePendency 
	 *   删除好友申请
	 * params:
	 *   cbOk	- function()类型, 成功时回调函数
	 *   cbErr	- function(err)类型, 失败时回调函数, err为错误对象
	 * return:
	 *   (无)
	 */
	deletePendency: function(options,cbOk, cbErr) {},
        
	/* function responseFriend 
	 *   响应好友申请
	 * params:
	 *   cbOk	- function()类型, 成功时回调函数
	 *   cbErr	- function(err)类型, 失败时回调函数, err为错误对象
	 * return:
	 *   (无)
	 */
	responseFriend: function(options,cbOk, cbErr) {},
        
	/* function getAllFriend
	 *   拉取我的好友
	 * params:
	 *   cbOk	- function()类型, 成功时回调函数
	 *   cbErr	- function(err)类型, 失败时回调函数, err为错误对象
	 * return:
	 *   (无)
	 */
	getAllFriend: function(options,cbOk, cbErr) {},
        
	/* function deleteFriend
	 *   删除好友
	 * params:
	 *   cbOk	- function()类型, 成功时回调函数
	 *   cbErr	- function(err)类型, 失败时回调函数, err为错误对象
	 * return:
	 *   (无)
	 */
	deleteFriend: function(options,cbOk, cbErr) {},
        
	/* function addBlackList 
	 *   增加黑名单
	 * params:
	 *   cbOk	- function()类型, 成功时回调函数
	 *   cbErr	- function(err)类型, 失败时回调函数, err为错误对象
	 * return:
	 *   (无)
	 */
	addBlackList: function(options,cbOk, cbErr) {},
        
	/* function getBlackList  
	 *   删除黑名单
	 * params:
	 *   cbOk	- function()类型, 成功时回调函数
	 *   cbErr	- function(err)类型, 失败时回调函数, err为错误对象
	 * return:
	 *   (无)
	 */
	getBlackList: function(options,cbOk, cbErr) {},
        
	/* function deleteBlackList  
	 *   我的黑名单
	 * params:
	 *   cbOk	- function()类型, 成功时回调函数
	 *   cbErr	- function(err)类型, 失败时回调函数, err为错误对象
	 * return:
	 *   (无)
	 */
	deleteBlackList: function(options,cbOk, cbErr) {},
        
	/* function uploadPic  
	 *   上传图片
	 * params:
	 *   options	- 请求参数，详见api文档
	 *   cbOk	- function()类型, 成功时回调函数
	 *   cbErr	- function(err)类型, 失败时回调函数, err为错误对象
	 * return:
	 *   (无)
	 */
	uploadPic: function(options,cbOk, cbErr) {},
        
	/* function createGroup  
	 *   创建群
	 * params:
	 *   options	- 请求参数，详见api文档
	 *   cbOk	- function()类型, 成功时回调函数
	 *   cbErr	- function(err)类型, 失败时回调函数, err为错误对象
	 * return:
	 *   (无)
	 */
	createGroup: function(options,cbOk, cbErr) {},
        
	/* function applyJoinGroup  
	 *   申请加群
	 * params:
	 *   options	- 请求参数，详见api文档
	 *   cbOk	- function()类型, 成功时回调函数
	 *   cbErr	- function(err)类型, 失败时回调函数, err为错误对象
	 * return:
	 *   (无)
	 */
	applyJoinGroup: function(options,cbOk, cbErr) {},
        
	/* function handleApplyJoinGroup  
	 *   处理申请加群(同意或拒绝)
	 * params:
	 *   options	- 请求参数，详见api文档
	 *   cbOk	- function()类型, 成功时回调函数
	 *   cbErr	- function(err)类型, 失败时回调函数, err为错误对象
	 * return:
	 *   (无)
	 */
	handleApplyJoinGroup: function(options,cbOk, cbErr) {},
        
	/* function deleteApplyJoinGroupPendency  
	 *   删除加群申请
	 * params:
	 *   options	- 请求参数，详见api文档
	 *   cbOk	- function()类型, 成功时回调函数
	 *   cbErr	- function(err)类型, 失败时回调函数, err为错误对象
	 * return:
	 *   (无)
	 */
	deleteApplyJoinGroupPendency: function(options,cbOk, cbErr) {},
        
        
	/* function quitGroup  
	 *  主动退群
	 * params:
	 *   options	- 请求参数，详见api文档
	 *   cbOk	- function()类型, 成功时回调函数
	 *   cbErr	- function(err)类型, 失败时回调函数, err为错误对象
	 * return:
	 *   (无)
	 */
	quitGroup: function(options,cbOk, cbErr) {},
        
	/* function getGroupPublicInfo  
	 *   读取群公开资料-高级接口
	 * params:
	 *   options	- 请求参数，详见api文档
	 *   cbOk	- function()类型, 成功时回调函数
	 *   cbErr	- function(err)类型, 失败时回调函数, err为错误对象
	 * return:
	 *   (无)
	 */
	getGroupPublicInfo: function(options,cbOk, cbErr) {},
        
	/* function getGroupInfo  
	 *   读取群详细资料-高级接口
	 * params:
	 *   options	- 请求参数，详见api文档
	 *   cbOk	- function()类型, 成功时回调函数
	 *   cbErr	- function(err)类型, 失败时回调函数, err为错误对象
	 * return:
	 *   (无)
	 */
	getGroupInfo: function(options,cbOk, cbErr) {},
        
	/* function modifyGroupBaseInfo  
	 *   修改群基本资料
	 * params:
	 *   options	- 请求参数，详见api文档
	 *   cbOk	- function()类型, 成功时回调函数
	 *   cbErr	- function(err)类型, 失败时回调函数, err为错误对象
	 * return:
	 *   (无)
	 */
	modifyGroupBaseInfo: function(options,cbOk, cbErr) {},
        
	/* function destroyGroup  
	 *  解散群
	 * params:
	 *   options	- 请求参数，详见api文档
	 *   cbOk	- function()类型, 成功时回调函数
	 *   cbErr	- function(err)类型, 失败时回调函数, err为错误对象
	 * return:
	 *   (无)
	 */
	destroyGroup: function(options,cbOk, cbErr) {},
        
	/* function getJoinedGroupListHigh  
	 *   获取我的群组-高级接口
	 * params:
	 *   options	- 请求参数，详见api文档
	 *   cbOk	- function()类型, 成功时回调函数
	 *   cbErr	- function(err)类型, 失败时回调函数, err为错误对象
	 * return:
	 *   (无)
	 */
	getJoinedGroupListHigh: function(options,cbOk, cbErr) {},
        
	/* function getGroupMemberInfo  
	 *   获取群组成员列表
	 * params:
	 *   options	- 请求参数，详见api文档
	 *   cbOk	- function()类型, 成功时回调函数
	 *   cbErr	- function(err)类型, 失败时回调函数, err为错误对象
	 * return:
	 *   (无)
	 */
	getGroupMemberInfo: function(options,cbOk, cbErr) {},
        
	/* function addGroupMember  
	 *   邀请好友加群
	 * params:
	 *   options	- 请求参数，详见api文档
	 *   cbOk	- function()类型, 成功时回调函数
	 *   cbErr	- function(err)类型, 失败时回调函数, err为错误对象
	 * return:
	 *   (无)
	 */
	addGroupMember: function(options,cbOk, cbErr) {},
        
	/* function modifyGroupMember  
	 *   修改群成员资料（角色或者群消息提类型示）
	 * params:
	 *   options	- 请求参数，详见api文档
	 *   cbOk	- function()类型, 成功时回调函数
	 *   cbErr	- function(err)类型, 失败时回调函数, err为错误对象
	 * return:
	 *   (无)
	 */
	modifyGroupMember: function(options,cbOk, cbErr) {},
        
	/* function forbidSendMsg  
	 *   设置群成员禁言时间
	 * params:
	 *   options	- 请求参数，详见api文档
	 *   cbOk	- function()类型, 成功时回调函数
	 *   cbErr	- function(err)类型, 失败时回调函数, err为错误对象
	 * return:
	 *   (无)
	 */
	forbidSendMsg: function(options,cbOk, cbErr) {},
        
	/* function deleteGroupMember  
	 *   删除群成员
	 * params:
	 *   options	- 请求参数，详见api文档
	 *   cbOk	- function()类型, 成功时回调函数
	 *   cbErr	- function(err)类型, 失败时回调函数, err为错误对象
	 * return:
	 *   (无)
	 */
	deleteGroupMember: function(options,cbOk, cbErr) {},
        
        /* function sendCustomGroupNotify  
	 *   发送自定义群通知
	 * params:
	 *   options	- 请求参数，详见api文档
	 *   cbOk	- function()类型, 成功时回调函数
	 *   cbErr	- function(err)类型, 失败时回调函数, err为错误对象
	 * return:
	 *   (无)
	 */
	sendCustomGroupNotify: function(options,cbOk, cbErr) {},

	/* class webim.Msg
	 *   一条消息的描述类, 消息发送、接收的API中都会涉及此类型的对象
	 * properties:
	 *   sess	- Session object-ref, 消息所属的会话(e.g:我与好友A的C2C会话，我与群组G的GROUP会话)
	 *   isSend	- Boolean, true表示是我发出消息, false表示是发给我的消息)
	 *   seq	- Integer, 消息序列号, 用于判断消息是否同一条
	 *   random	- Integer, 消息随机数,用于判断消息是否同一条
	 *   time	- Integer, 消息时间戳, 为unix timestamp
	 *   fromAccount -String,  消息发送者帐号
         *   subType -Integer,  消息子类型，c2c消息时，0-表示普通消息；群消息时，0-普通消息，1-点赞消息，2-提示消息
	 *   fromAccountNick -String,  消息发送者昵称
	 *   elems	- Array of webim.Msg.Elem, 描述消息内容的元素列表
	 * constructor:
	 *   Msg(sess, isSend, seq,random time,fromAccount) - 构造函数, 参数定义同上面properties中定义
	 * methods:
	 *   addText(text)	- 向elems中添加一个TEXT元素
	 *   addFace(face)	- 向elems中添加一个FACE元素
	 *   toHtml()		- 转成可展示的html String
	 *addFace
	 * sub-class webim.Msg.Elem
	 *   消息中一个组成元素的描述类, 一条消息的内容被抽象描述为N个元素的有序列表
	 * properties:
	 *   type	- 元素类型, 目前有TEXT(文本)、FACE(表情)、IMAGE(图片)等
	 *   content- 元素内容体, 当TEXT时为String, 当PIC时为UrlString
	 * constructor:
	 *   Elem(type, content) - 构造函数, 参数定义同上面properties中定义
	 *
	 * sub-class webim.Msg.Elem.TextElem
	 *   文本
	 * properties:
	 *   text  - String 内容
	 * constructor:
	 *   TextElem(text) - 构造函数, 参数定义同上面properties中定义
         *   
	 * sub-class webim.Msg.Elem.FaceElem
	 *   表情
	 * properties:
	 *   index  - Integer 表情索引, 用户自定义
	 *   data   - String 额外数据，用户自定义
	 * constructor:
	 *   FaceElem(index,data) - 构造函数, 参数定义同上面properties中定义
         *   
	 *
	 */
	Msg: function(sess, isSend, seq, random,time,fromAccount,subType,fromAccountNick) {/*Class constructor*/},

	/* singleton object MsgStore
	 * webim.MsgStore是消息数据的Model对象(参考MVC概念), 它提供接口访问当前存储的会话和消息数据
	 * 下面说明下会话数据类型: Session
	 *
	 * class Session
	 *   一个Session对象描述一个会话，会话可简单理解为最近会话列表的一个条目，它由两个字段唯一标识:
	 *     type	- String, 会话类型(如"C2C", "GROUP", ...)
	 *     id	- String, 会话ID(如C2C类型中为对方帐号,"C2C"时为好友ID,"GROUP"时为群ID)
	 * properties:
	 *   (Session对象未对外暴露任何属性字段, 所有访问通过下面的getter方法进行)
	 * methods:
	 *   type()		- String, 返回会话类型,"C2C"表示与好友私聊，"GROUP"表示群聊
	 *   id()		- String, 返回会话ID 
	 *   name()		- String, 返回会话标题(如C2C类型中为对方的昵称)
	 *   icon()		- String, 返回会话图标(对C2C类型中为对方的头像URL)
	 *   unread()           - Integer, 返回会话未读条数
	 *   time()		- Integer, 返回会话最后活跃时间, 为unix timestamp
	 *   curMaxMsgSeq()	- Integer, 返回会话最大消息序列号
	 *   msgCount()	- Integer, 返回会话中所有消息条数
	 *   msg(index)	- webim.Msg, 返回会话中第index条消息
	 */
	MsgStore: {
		/* function sessMap
		 *   获取所有会话
		 * return:
		 *   所有会话对象
		 */
		sessMap: function() {return {/*Object*/};},
		/* function sessCount
		 *   获取当前会话的个数
		 * return:
		 *   Integer, 会话个数
		 */
		sessCount: function() {return 0;},

		/* function sessByTypeId
		 *   根据会话类型和会话ID取得相应会话
		 * params:
		 *   type	- String, 会话类型(如"C2C", "GROUP", ...)
		 *   id		- String, 会话ID(如对方ID)
		 * return:
		 *   Session, 会话对象(说明见上面)
		 */
		sessByTypeId: function(type, id) {return {/*Session Object*/};},
		/* function delSessByTypeId
		 *   根据会话类型和会话ID删除相应会话
		 * params:
		 *   type	- String, 会话类型(如"C2C", "GROUP", ...)
		 *   id		- String, 会话ID(如对方ID)
		 * return:
		 *   Boolean, 布尔类型
		 */
		delSessByTypeId: function(type, id) {return true;},
                
		/* function resetCookieAndSyncFlag
		 *   重置上一次读取新c2c消息Cookie和是否继续拉取标记
		 * return:
		 *   
		 */
		resetCookieAndSyncFlag: function() {}
	}

};

/* webim API implementation
 */
(function(webim) {
        //sdk版本
        var SDK={
            'VERSION':'1.6.0',//sdk版本号
            'APPID':'537047540'//web im sdk 版本 APPID
        };
    
        //是否启用正式环境，默认启用
        var isAccessFormaEnvironment=true;
        //是否直接透传tinyid和a2
        var isUseTinyid=true;
        
        //后台接口主机
        var SRV_HOST={
            'FORMAL':{
                'COMMON':'https://webim.tim.qq.com',
                'PIC':'https://pic.tim.qq.com',
                'BIG_GROUP':'https://webapi.tim.qq.com'
            },
            'TEST':{
                'COMMON':'https://test.tim.qq.com',
                'PIC':'https://pic.tim.qq.com',
                'BIG_GROUP':'https://test.tim.qq.com'
            }
        };
        
        var BROWSER_INFO={};//浏览器版本信息
        //是否为ie9（含）以下
        var lowerBR=false;
        
        //服务名称
        var SRV_NAME={
            'OPEN_IM':'openim',//私聊（拉取未读c2c消息，长轮询，c2c消息已读上报等）服务名
            'GROUP':'group_open_http_svc',//群组管理（拉取群消息，创建群，群成员管理，群消息已读上报等）服务名
            'FRIEND':'sns',//关系链管理（好友管理，黑名单管理等）服务名
            'PROFILE':'profile',//资料管理（查询，设置个人资料等）服务名
            'PIC':'openpic',//图片（上传图片）服务名
            'BIG_GROUP':'group_open_http_noauth_svc',//直播大群 群组管理（申请加群）服务名
            'BIG_GROUP_LONG_POLLING':'group_open_long_polling_http_noauth_svc',//直播大群 长轮询（拉取消息等）服务名
            'IM_OPEN_STAT':'imopenstat'//质量上报，统计接口错误率
        };
        
        //不同服务对应的版本号
        var SRV_NAME_VER={
            'openim':'v4',
            'group_open_http_svc':'v3',
            'sns':'v3',
            'profile':'v3',
            'openpic':'v4',
            'group_open_http_noauth_svc':'v1',
            'group_open_long_polling_http_noauth_svc':'v1',
            'imopenstat':'v4'
        };
        
        //不同的命令名对应的上报类型ID
        var CMD_EVENT_ID_MAP={
            'login':1,//登录
            'pic_up':3,//上传图片
            'apply_join_group':9,//申请加入群组
            'create_group':10,//创建群组
            'longpolling':18,//普通长轮询
            'send_group_msg':19,//群聊
            'sendmsg':20//私聊
        };
        
        //聊天类型
        var SESSION_TYPE={
            'C2C':'C2C',//私聊
            'GROUP':'GROUP'//群聊
        };
        
        //消息最大长度（字节）
        var MSG_MAX_LENGTH={
            'C2C':12000,//私聊消息
            'GROUP':8898//群聊
        };
        
        //后台接口返回类型
        var ACTION_STATUS={
            'OK':'OK',//成功
            'FAIL':'FAIL'//失败
        };
        
        var ERROR_CODE_CUSTOM=99999;//自定义后台接口返回错误码
        
        //消息元素类型
        var MSG_ELEMENT_TYPE={
            'TEXT':'TIMTextElem',//文本
            'FACE':'TIMFaceElem',//表情
            'IMAGE':'TIMImageElem',//图片
            'CUSTOM':'TIMCustomElem',//自定义
            'SOUND':'TIMSoundElem',//语音,只支持显示
            'FILE':'TIMFileElem',//文件,只支持显示
            'LOCATION':'TIMLocationElem',//地理位置
            'GROUP_TIP':'TIMGroupTipElem'//群提示消息,只支持显示
        };
        
        //图片类型
        var IMAGE_TYPE={
            'ORIGIN':1,//原图
            'LARGE':2,//缩略大图
            'SMALL':3//缩略小图
        };
        
        //下载文件配置
        var DOWNLOAD_FILE={
            'BUSSINESS_ID':'10001',//下载文件业务ID
            'AUTH_KEY':'617574686b6579',//下载文件authkey
            'SERVER_IP':'182.140.186.147'//下载文件服务器IP
        };
        
        //下载文件类型
        var DOWNLOAD_FILE_TYPE={
            "SOUND":2106,//语音
            "FILE":2107//普通文件
        };
        
        //长轮询消息类型
        var LONG_POLLINNG_EVENT_TYPE={
            "C2C":1,//新的c2c消息通知
            "GROUP_COMMON":3,//新的群普通消息
            "GROUP_TIP":4,//新的群提示消息
            "GROUP_SYSTEM":5,//新的群系统消息
            "GROUP_TIP2":6,//新的群提示消息2
            "FRIEND_NOTICE":7,//好友系统通知
            "PROFILE_NOTICE":8//资料系统通知
        };
        
        //c2c消息子类型
        var C2C_MSG_SUB_TYPE={
            "COMMON":0//普通消息
        };
        
        //群消息子类型
        var GROUP_MSG_SUB_TYPE={
            "COMMON":0,//普通消息
            "LOVEMSG":1,//点赞消息
            "TIP":2,//提示消息
            "REDPACKET":3//红包消息
        };
        
        //群消息优先级类型
        var GROUP_MSG_PRIORITY_TYPE={
            "REDPACKET":1,//红包消息
            "COMMON":2,//普通消息
            "LOVEMSG":3//点赞消息
        };
        
        //群提示消息类型
        var GROUP_TIP_TYPE={
            "JOIN":1,//加入群组
            "QUIT":2,//退出群组
            "KICK":3,//被踢出群组
            "SET_ADMIN":4,//被设置为管理员
            "CANCEL_ADMIN":5,//被取消管理员
            "MODIFY_GROUP_INFO":6,//修改群资料
            "MODIFY_MEMBER_INFO":7//修改群成员信息
        };
        
        //群提示消息-群资料变更类型
        var GROUP_TIP_MODIFY_GROUP_INFO_TYPE={
            "FACE_URL":1,//修改群头像URL
            "NAME":2,//修改群名称
            "OWNER":3,//修改群主
            "NOTIFICATION":4,//修改群公告
            "INTRODUCTION":5//修改群简介
        };
        
        //群系统消息类型
        var GROUP_SYSTEM_TYPE={
            "JOIN_GROUP_REQUEST":1,//申请加群请求（只有管理员会收到）
            "JOIN_GROUP_ACCEPT":2,//申请加群被同意（只有申请人能够收到）
            "JOIN_GROUP_REFUSE":3,//申请加群被拒绝（只有申请人能够收到）
            "KICK":4,//被管理员踢出群(只有被踢者接收到)
            "DESTORY":5,//群被解散(全员接收)
            "CREATE":6,//创建群(创建者接收, 不展示)
            "INVITED_JOIN_GROUP_REQUEST":7,//邀请加群(被邀请者接收)
            "QUIT":8,//主动退群(主动退出者接收, 不展示)
            "SET_ADMIN":9,//设置管理员(被设置者接收)
            "CANCEL_ADMIN":10,//取消管理员(被取消者接收)
            "REVOKE":11,//群已被回收(全员接收, 不展示)
            "CUSTOM":255//用户自定义通知(默认全员接收)
        };
        
        //好友系统通知子类型
        var FRIEND_NOTICE_TYPE={
            "FRIEND_ADD":1,//好友表增加
            "FRIEND_DELETE":2,//好友表删除
            "PENDENCY_ADD":3,//未决增加
            "PENDENCY_DELETE":4,//未决删除
            "BLACK_LIST_ADD":5,//黑名单增加
            "BLACK_LIST_DELETE":6,//黑名单删除
            "PENDENCY_REPORT":7,//未决已读上报
            "FRIEND_UPDATE":8//好友数据更新
        };
        
        //资料系统通知子类型
        var PROFILE_NOTICE_TYPE={
            "PROFILE_MODIFY":1//资料修改
        };
        
        //腾讯登录服务错误码（用于托管模式）
        var TLS_ERROR_CODE={
            'OK':0,//成功
            'SIGNATURE_EXPIRATION':11//用户身份凭证过期
        };
        
        //长轮询连接状态
        var CONNECTION_STATUS={
            'INIT':-1,//初始化
            'ON':0,//连接正常
            'RECONNECT':1,//连接恢复正常
            'OFF':9999//连接已断开,可能是用户网络问题，或者长轮询接口报错引起的
        };
        
        var UPLOAD_PIC_BUSSINESS_TYPE={//图片业务类型
            'GROUP_MSG':1,//私聊图片
            'C2C_MSG':2,//群聊图片
            'USER_HEAD':3,//用户头像
            'GROUP_HEAD':4//群头像
        };
        
        var FRIEND_WRITE_MSG_ACTION={//好友输入消息状态
            'ING':14,//正在输入
            'STOP':15//停止输入
        };
        
        //ajax默认超时时间，单位：毫秒
        var ajaxDefaultTimeOut=15000;
        
        //大群长轮询接口返回正常时，延时一定时间再发起下一次请求
        var OK_DELAY_TIME=1000;
        
        //大群长轮询接口发生错误时，延时一定时间再发起下一次请求
        var ERROR_DELAY_TIME=5000;
        
        //群提示消息最多显示人数
        var GROUP_TIP_MAX_USER_COUNT=10;
        
        //长轮询连接状态
        var curLongPollingStatus=CONNECTION_STATUS.INIT;
        
        //当长轮询连接断开后，是否已经回调过
        var longPollingOffCallbackFlag=false;
        
        //当前长轮询返回错误次数
        var curLongPollingRetErrorCount=0;
        
        //长轮询默认超时时间，单位：毫秒
        var longPollingDefaultTimeOut=120000;
        
        //长轮询返回错误次数达到一定值后，发起新的长轮询请求间隔时间，单位：毫秒
        var longPollingIntervalTime=5000;
        
        //没有新消息时，长轮询返回60008错误码是正常的
        var longPollingTimeOutErrorCode=60008;
        
        //当前大群长轮询返回错误次数
        var curBigGroupLongPollingRetErrorCount=0;
        
        //最大允许长轮询返回错误次数
        var LONG_POLLING_MAX_RET_ERROR_COUNT=10;
        
        //ie7/8/9采用jsonp方法解决ajax跨域限制
        var jsonpRequestId=0;//jsonp请求id
        //最新jsonp请求返回的json数据
        var jsonpLastRspData=null;
        //兼容ie7/8/9,jsonp回调函数
        var jsonpCallback=null;
        
        var uploadResultIframeId=0;//用于上传图片的iframe id
        
        //错误码
        var ERROR={};
        //当前登录用户
	var ctx = {
                sdkAppID:null,
                appIDAt3rd:null,
                accountType:null,
                identifier:null,
                tinyid:null,
                identifierNick:null,
                userSig:null,
                a2:null,
		contentType: 'json',
		apn: 1
	};
	var opt = {};
        var xmlHttpObjSeq=0;//ajax请求id
	var xmlHttpObjMap={};//发起的ajax请求
	var curSeq =0;//消息seq
        var tempC2CMsgList=[];//新c2c消息临时缓存
        var C2CHitoryMsgKeyMap={};//记录下一次拉取c2c漫游消息的msgkey
        var tempC2CHistoryMsgList=[];//漫游c2c消息临时缓存
        
        var maxApiReportItemCount=20;//一次最多上报条数
        var apiReportItems=[];//暂存api接口质量上报数据
        
        
        //表情标识字符和索引映射关系对象，用户可以自定义
        var emotionDataIndexs = {
                "[惊讶]":0,
		"[撇嘴]":1,
		"[色]":2,
		"[发呆]":3,
		"[得意]":4,
		"[流泪]":5,
		"[害羞]":6,
		"[闭嘴]":7,
		"[睡]":8,
		"[大哭]":9,
		"[尴尬]":10,
		"[发怒]":11,
		"[调皮]":12,
		"[龇牙]":13,
		"[微笑]":14,
		"[难过]":15,
		"[酷]":16,
		"[冷汗]":17,
		"[抓狂]":18,
		"[吐]":19,
		"[偷笑]":20,
		"[可爱]":21,
		"[白眼]":22,
		"[傲慢]":23,
		"[饿]":24,
		"[困]":25,
		"[惊恐]":26,
		"[流汗]":27,
		"[憨笑]":28,
		"[大兵]":29,
		"[奋斗]":30,
		"[咒骂]":31,
		"[疑问]":32,
		"[嘘]":33,
		"[晕]":34	
        };
        
        //表情对象，用户可以自定义
        var emotions = {
                "0":["[惊讶]",""],
		"1":["[撇嘴]",""],
		"2":["[色]",""],
		"3":["[发呆]",""],
		"4":["[得意]",""],
		"5":["[流泪]",""],
		"6":["[害羞]",""],
		"7":["[闭嘴]",""],
		"8":["[睡]",""],
		"9":["[大哭]",""],
		"10":["[尴尬]",""],
		"11":["[发怒]",""],
		"12":["[调皮]",""],
		"13":["[龇牙]",""],
		"14":["[微笑]",""],
		"15":["[难过]",""],
		"16":["[酷]",""],
		"17":["[冷汗]",""],
		"18":["[抓狂]",""],
		"19":["[吐]",""],
		"20":["[偷笑]",""],
		"21":["[可爱]",""],
		"22":["[白眼]",""],
		"23":["[傲慢]",""],
		"24":["[饿]",""],
		"25":["[困]",""],
		"26":["[惊恐]",""],
                "27":["[流汗]",""],
		"28":["[憨笑]",""],
		"29":["[大兵]",""],
		"30":["[奋斗]",""],
		"31":["[咒骂]",""],
		"32":["[疑问]",""],
		"33":["[嘘]",""],
		"34":["[晕]",""]
        };
        //工具类
	var tool = new function() {
		
                //格式化时间戳
		this.formatTimeStamp = function(time,format) {
                    if(time==0){
                        return time;
                    }
                    format=format || 'yyyy-MM-dd hh:mm:ss';
                    var date = new Date(time * 1000);
                    var formatTime;
                    var o = {
                        "M+": date.getMonth() + 1, //月份 
                        "d+": date.getDate(), //日 
                        "h+": date.getHours(), //小时 
                        "m+": date.getMinutes(), //分 
                        "s+": date.getSeconds() //秒   
                    };
                    if (/(y+)/.test(format)) 
                        formatTime = format.replace(RegExp.$1, (date.getFullYear() + "").substr(4 - RegExp.$1.length));
                    for (var k in o){
                        if (new RegExp("(" + k + ")").test(formatTime)) 
                            formatTime = formatTime.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
                    } 
                    return formatTime;
                };
                //根据群类型英文名转换成中文名
                this.groupTypeEn2Ch = function(type_en) {
                        var type_ch = null;
                        switch (type_en) {
                            case 'Public':
                                type_ch = '公开群';
                                break;
                            case 'ChatRoom':
                                type_ch = '聊天室';
                                break;
                            case 'Private':
                                type_ch = '讨论组';
                                break;
                            case 'AVChatRoom':
                                type_ch = '直播聊天室';
                                break;
                            default:
                                type_ch = type_en;
                                break;
                        }
                        return type_ch;
                };
                //根据群类型中文名转换成英文名
                this.groupTypeCh2En = function(type_ch) {
                        var type_en = null;
                        switch (type_ch) {
                            case '公开群':
                                type_en = 'Public';
                                break;
                            case '聊天室':
                                type_en = 'ChatRoom';
                                break;
                            case '讨论组':
                                type_en = 'Private';
                                break;
                            case '直播聊天室':
                                type_en = 'AVChatRoom';
                                break;
                            default:
                                type_en = type_ch;
                                break;
                        }
                        return type_en;
                };
                //根据群身份英文名转换成群身份中文名
                this.groupRoleEn2Ch = function(role_en) {
                        var role_ch = null;
                        switch (role_en) {
                            case 'Member':
                                role_ch = '成员';
                                break;
                            case 'Admin':
                                role_ch = '管理员';
                                break;
                            case 'Owner':
                                role_ch = '群主';
                                break;
                            default:
                                role_ch = role_en;
                                break;
                        }
                        return role_ch;
                };
                //根据群身份中文名转换成群身份英文名
                this.groupRoleCh2En = function(role_ch) {
                        var role_en = null;
                        switch (role_ch) {
                            case '成员':
                                role_en = 'Member';
                                break;
                            case '管理员':
                                role_en = 'Admin';
                                break;
                            case '群主':
                                role_en = 'Owner';
                                break;
                            default:
                                role_en = role_ch;
                                break;
                        }
                        return role_en;
                };
                //根据群消息提示类型英文转换中文
                this.groupMsgFlagEn2Ch = function(msg_flag_en) {
                        var msg_flag_ch = null;
                        switch (msg_flag_en) {
                            case 'AcceptAndNotify':
                                msg_flag_ch = '接收并提示';
                                break;
                            case 'AcceptNotNotify':
                                msg_flag_ch = '接收不提示';
                                break;
                            case 'Discard':
                                msg_flag_ch = '屏蔽';
                                break;
                            default:
                                msg_flag_ch = msg_flag_en;
                                break;
                        }
                        return msg_flag_ch;
                };
                //根据群消息提示类型中文名转换英文名
                this.groupMsgFlagCh2En = function(msg_flag_ch) {
                        var msg_flag_en = null;
                        switch (msg_flag_ch) {
                            case '接收并提示':
                                msg_flag_en = 'AcceptAndNotify';
                                break;
                            case '接收不提示':
                                msg_flag_en = 'AcceptNotNotify';
                                break;
                            case '屏蔽':
                                msg_flag_en = 'Discard';
                                break;
                            default:
                                msg_flag_en = msg_flag_ch;
                                break;
                        }
                        return msg_flag_en;
                };
                //将空格和换行符转换成HTML标签
                this.formatText2Html=function(text){
                    var html=text;
                    if(html){
                        html=this.xssFilter(html);//用户昵称或群名称等字段会出现脚本字符串
                        html=html.replace(/ /g,"&nbsp;");
                        html=html.replace(/\n/g,"<br/>");
                    }
                    return html;
                };
                //将HTML标签转换成空格和换行符
                this.formatHtml2Text=function(html){
                    var text=html;
                    if(text){
                        text=text.replace(/&nbsp;/g," ");
                        text=text.replace(/<br\/>/g,"\n");
                    }
                    return text;
                };
                //获取字符串所占字节数 
                this.getStrBytes=function(str){
                    if (str == null) return 0;
                    if (typeof str != "string"){
                        str += "";
                    }
                    return str.replace(/[^x00-xff]/g, "012").length;
                };
                //防止XSS攻击
                this.xssFilter = function (val) {
                    val = val.toString();
                    val = val.replace(/[<]/g, "&lt;");
                    val = val.replace(/[>]/g, "&gt;");
                    val = val.replace(/"/g, "&quot;");
                    //val = val.replace(/'/g, "&#039;");
                    return val;
                };
             
                //去掉头尾空白符
                this.trimStr=function(str){
                    if(!str) return '';
                    str=str.toString();
                    return str.replace(/(^\s*)|(\s*$)/g,"");
                };
                //判断是否为8位整数
                this.validNumber=function(str){
                    str=str.toString();
                    return str.match(/(^\d{1,8}$)/g);
                };
                this.getReturnError=function(errorInfo,errorCode){
                    if(!errorCode){
                        errorCode=-100;
                    }
                    var error={
                        'ActionStatus':ACTION_STATUS.FAIL,
                        'ErrorCode':errorCode,
                        'ErrorInfo':errorInfo+"["+errorCode+"]"
                    };
                    return error;
                };
                //设置cookie
                //name 名字
                //value 值
                //expires 有效期(单位：秒)
                //path 
                //domain 作用域
                this.setCookie=function(name,value,expires,path,domain){
                    
                    var exp  = new Date();
                    exp.setTime(exp.getTime() + expires*1000);
                    document.cookie = name + "="+ escape (value) + ";expires=" + exp.toGMTString();
                };
                //获取cookie
                this.getCookie=function (name){
                    var result = document.cookie.match(new RegExp("(^| )"+name+"=([^;]*)(;|$)"));
                    if(result != null){
                        return unescape(result[2]);
                    }  
                    return null;
                };
                //删除cookie
                this.delCookie=function (name){
                    var exp = new Date();
                    exp.setTime(exp.getTime() - 1);
                    var value=this.getCookie(name);
                    if(value!=null) 
                        document.cookie= name + "="+escape (value)+";expires="+exp.toGMTString();
                };
                //根据名字获取url参数值
                this.getQueryString=function(name) { 
                    var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i"); 
                    var r = window.location.search.substr(1).match(reg); 
                    if (r != null) return unescape(r[2]); 
                    return null; 
                };
                //判断IE版本号，ver表示版本号
                this.isIE = function(ver){
                    var b = document.createElement('b')
                    b.innerHTML = '<!--[if IE ' + ver + ']><i></i><![endif]-->'
                    return b.getElementsByTagName('i').length === 1;
                };
                //判断浏览器版本
                this.getBrowserInfo=function(){
                    var Sys={};
                    var ua=navigator.userAgent.toLowerCase();
                    log.info('navigator.userAgent='+ua);
                    var s;
                    (s=ua.match(/msie ([\d.]+)/))?Sys.ie=s[1]:
                    (s=ua.match(/firefox\/([\d.]+)/))?Sys.firefox=s[1]:
                    (s=ua.match(/chrome\/([\d.]+)/))?Sys.chrome=s[1]:
                    (s=ua.match(/opera.([\d.]+)/))?Sys.opera=s[1]:
                    (s=ua.match(/version\/([\d.]+).*safari/))?Sys.safari=s[1]:0;
                    if(Sys.ie){//Js判断为IE浏览器
                        return {
                            'type':'ie',
                            'ver':Sys.ie
                        };
                    }
                    if(Sys.firefox){//Js判断为火狐(firefox)浏览器
                        return {
                            'type':'firefox',
                            'ver':Sys.firefox
                        };
                    }
                    if(Sys.chrome){//Js判断为谷歌chrome浏览器
                        return {
                            'type':'chrome',
                            'ver':Sys.chrome
                        }; 
                    }
                    if(Sys.opera){//Js判断为opera浏览器
                        return {
                            'type':'opera',
                            'ver':Sys.opera
                        };
                    }
                    if(Sys.safari){//Js判断为苹果safari浏览器
                        return {
                            'type':'safari',
                            'ver':Sys.safari
                        };
                    }
                    return {
                        'type':'unknow',
                        'ver':-1
                    };
                };
                  
	};
        
        //日志对象
        var log = new function () {
            
            var on=true;
            
            this.setOn=function(onFlag){
                on=onFlag;
            };
            
            this.getOn=function(){
                return on;  
            };

            this.error = function (logStr) {
                try {
                    on && console.error(logStr);
                } catch (e) {}
            };
            this.warn = function (logStr) {
                try {
                    on && console.warn(logStr);
                } catch (e) {}
            };
            this.info = function (logStr) {
                try {
                    on && console.info(logStr);
                } catch (e) {}
            };
            this.debug = function (logStr) {
                try {
                    on && console.debug(logStr);
                } catch (e) {}
            };
        };
	//获取unix时间戳
	var unixtime = function(d) {
		if (!d) d = new Date();
		return Math.round(d.getTime()/1000);
	};
        //时间戳转日期
	var fromunixtime = function(t) {
		return new Date(t*1000);
	};
        //获取下一个消息序号
	var nextSeq = function() {
                if(curSeq){
                    curSeq=curSeq+1;
                }else{
                    curSeq=Math.round(Math.random() * 10000000);
                }
		return curSeq;
	};
        //产生随机数
        var createRandom = function() {
		return  Math.round(Math.random() * 4294967296);
	};
        
        //睡眠
        var sleep=function(n) {
            var start = new Date().getTime();
            while(true)  if(new Date().getTime()-start > n) break;
        };
        
        //获取ajax请求对象
	var getXmlHttp = function() {
		var xmlhttp = null;
		if (window.XMLHttpRequest) {
			xmlhttp = new XMLHttpRequest();
		} else {
			try {
				xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
			} catch (e) {
				try {
					xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
				} catch (e) {
					return null;
				}
			}
		}
		return xmlhttp;
	}
        //发起ajax请求
	var ajaxRequest = function(meth, url, req, timeout,isLongPolling,cbOk, cbErr) {
                
                var xmlHttpObj = getXmlHttp();
             
                var error,errInfo;
		if (!xmlHttpObj){
                    errInfo = "创建请求失败";
                    var error=tool.getReturnError(errInfo,-1);
                    log.error(errInfo);
                    if (cbErr) cbErr(error);
                    return;
                }
                //保存ajax请求对象
                xmlHttpObjSeq++;
                xmlHttpObjMap[xmlHttpObjSeq]=xmlHttpObj;
                
		xmlHttpObj.open(meth, url, true);
		xmlHttpObj.onreadystatechange = function() {
			if (xmlHttpObj.readyState == 4) {
                                xmlHttpObjMap[xmlHttpObjSeq]=null;//清空
				if (xmlHttpObj.status == 200) {
					if (cbOk) cbOk(xmlHttpObj.responseText);
                                        xmlHttpObj=null;
				} else {
					var errInfo = "请求服务器失败,请检查你的网络是否正常";
                                        var error=tool.getReturnError(errInfo,-2);
                                        xmlHttpObj=null;
					//if (!isLongPolling && cbErr) cbErr(error);
					if (cbErr) cbErr(error);
				}
			}
		};
                xmlHttpObj.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
                //设置超时时间
                if(!timeout){
                    timeout=ajaxDefaultTimeOut;//设置ajax默认超时时间
                }
                if(timeout){
                    xmlHttpObj.timeout = timeout;
                    xmlHttpObj.ontimeout = function(event){
                        var errInfo = "请求服务器超时";
                        var error=tool.getReturnError(errInfo,-3);
                        xmlHttpObj=null;
                        if (cbErr) cbErr(error);
                    };
                }
                //
		xmlHttpObj.send(req);
	}
        //发起ajax请求（json格式数据）
	var ajaxRequestJson = function(meth, url, req, timeout,isLongPolling,cbOk, cbErr) {
		ajaxRequest(meth, url, JSON.stringify(req),timeout,isLongPolling,function(resp) {
			var json = null;
			//if (resp) eval('json=('+resp+');');//将返回的json字符串转换成json对象
			//if (resp) json=eval('('+resp+')');//将返回的json字符串转换成json对象
			if (resp) json=JSON.parse(resp);//将返回的json字符串转换成json对象
			if (cbOk) cbOk(json);
		}, cbErr);
	}
        //判断用户是否已登录
	var isLogin = function() {
		return ctx.sdkAppID && ctx.identifier;
	};
        //检查是否登录
	var checkLogin = function(cbErr,isNeedCallBack) {
		if (!isLogin()) {
                        if(isNeedCallBack){
                            var errInfo = "请登录";
                            var error=tool.getReturnError(errInfo,-4);
                            
                            if(cbErr) cbErr(error);
                        }
			return false;
		}
		return true;
	};
        
        //检查是否访问正式环境
        var isAccessFormalEnv=function(){
            return isAccessFormaEnvironment;
        };
        
        //根据不同的服务名和命令，获取对应的接口地址
	var getApiUrl = function(srvName,cmd,cbOk, cbErr) {
                var srvHost=SRV_HOST;
                if(isAccessFormalEnv()){
                    srvHost=SRV_HOST.FORMAL.COMMON;
                }else{
                    srvHost=SRV_HOST.TEST.COMMON;
                }
                if (srvName==SRV_NAME.PIC){
                    if(isAccessFormalEnv()){
                        srvHost=SRV_HOST.FORMAL.PIC;
                    }else{
                        srvHost=SRV_HOST.TEST.PIC;
                    }
                }
                //如果访问的接口是大群(长轮询和进群和退群)接口
                if (srvName==SRV_NAME.BIG_GROUP_LONG_POLLING || srvName==SRV_NAME.BIG_GROUP){
                    if(isAccessFormalEnv()){
                        host=SRV_HOST.FORMAL.BIG_GROUP;
                    }else{
                        host=SRV_HOST.TEST.BIG_GROUP;
                    }
                }
                var url=srvHost+'/'+SRV_NAME_VER[srvName]+'/'+srvName+'/'+cmd+'?websdkappid='+SDK.APPID+"&v="+SDK.VERSION;
                
                if(isLogin()){
                    if(cmd=='login'){
                        url+='&identifier='+encodeURIComponent(ctx.identifier)+'&usersig='+ctx.userSig;
                    }else{
                        if(ctx.tinyid && ctx.a2){
                            url+='&tinyid='+ctx.tinyid+'&a2='+ctx.a2;
                        }else{
                            if(cbErr){
                                log.error("tinyid或a2为空["+srvName+"]["+cmd+"]");
                                cbErr(tool.getReturnError("tinyid或a2为空["+srvName+"]["+cmd+"]",-5));
                                return false;
                            }
                        }
                    }
                    url+='&contenttype='+ctx.contentType;
                }
                url+='&sdkappid='+ctx.sdkAppID+'&accounttype='+ctx.accountType+'&apn='+ctx.apn+'&reqtime='+unixtime();
		return url;
	};
        
        //重置ajax请求
        var clearXmlHttpObjMap=function(){
            //遍历xmlHttpObjMap{}
            for ( var seq in xmlHttpObjMap ){ 
                var xmlHttpObj=xmlHttpObjMap[seq];
                if(xmlHttpObj){
                    xmlHttpObj.abort();//中断ajax请求(长轮询)
                    xmlHttpObjMap[xmlHttpObjSeq]=null;//清空
                }
            }
            xmlHttpObjSeq=0;
            xmlHttpObjMap={};
        };
        
        //重置sdk全局变量
        var clearSdk=function(){
            
            clearXmlHttpObjMap();
            
            //当前登录用户
            ctx = {
                sdkAppID:null,
                appIDAt3rd:null,
                accountType:null,
                identifier:null,
                identifierNick:null,
                userSig:null,
		contentType: 'json',
		apn: 1
            };
            opt = {};
            
            curSeq=0;
            
            //ie8,9采用jsonp方法解决ajax跨域限制
            jsonpRequestId=0;//jsonp请求id
            //最新jsonp请求返回的json数据
            jsonpLastRspData=null;
            
            apiReportItems=[];
            
            MsgManager.clear();
        };
        
        //登录
        var _login=function(loginInfo,listeners,options,cbOk,cbErr){
            
                clearSdk();
                
                if (options) opt = options;
                if(opt.isAccessFormalEnv==false){
                    isAccessFormaEnvironment=opt.isAccessFormalEnv;
                }
                if(opt.isLogOn==false){
                    log.setOn(opt.isLogOn);
                }
                /*
                if(opt.emotions){
                    emotions=opt.emotions;
                    webim.Emotions= emotions;
                }
                if(opt.emotionDataIndexs){
                    emotionDataIndexs=opt.emotionDataIndexs;
                    webim.EmotionDataIndexs= emotionDataIndexs;
                }*/
                
                if(!loginInfo){
                    if(cbErr){
                        cbErr(tool.getReturnError("loginInfo is empty",-6));
                        return;
                    }
                }
                if(!loginInfo.sdkAppID){
                    if(cbErr){
                        cbErr(tool.getReturnError("loginInfo.sdkAppID is empty",-7));
                        return;
                    }
                }
                if(!loginInfo.accountType){
                    if(cbErr){
                        cbErr(tool.getReturnError("loginInfo.accountType is empty",-8));
                        return;
                    }
                }
                
                if(loginInfo.identifier){
                    ctx.identifier = loginInfo.identifier.toString();
                }
                if(loginInfo.identifier && !loginInfo.userSig){
                    if(cbErr){
                        cbErr(tool.getReturnError("loginInfo.userSig is empty",-9));
                        return;
                    }
                }
                if(loginInfo.userSig){
                    ctx.userSig = loginInfo.userSig.toString();
                }
                ctx.sdkAppID = loginInfo.sdkAppID;
                ctx.accountType = loginInfo.accountType;
		
                if(ctx.identifier && ctx.userSig){//带登录态
                    //登录
                    proto_login(
                         function(identifierNick){
                             MsgManager.init(
                                        listeners,
                                        function(mmInitResp){
                                            if(cbOk){
                                                mmInitResp.identifierNick=identifierNick;
                                                cbOk(mmInitResp);
                                            }
                                        },cbErr
                             );
                         },
                         cbErr
                    );
                }else{//不带登录态，进入直播场景sdk
                    MsgManager.init(
                                listeners,
                                cbOk,
                                cbErr
                    );
                }
        };
        
        //初始化浏览器信息
        var initBrowserInfo=function(){
                //初始化浏览器类型
                BROWSER_INFO=tool.getBrowserInfo();
                log.info('BROWSER_INFO: type='+BROWSER_INFO.type+', ver='+BROWSER_INFO.ver);
                if (BROWSER_INFO.type=="ie") {
                    if (parseInt(BROWSER_INFO.ver) < 10) {
                        lowerBR = true;
                    }
                }
        };
        
        //接口质量上报
        var reportApiQuality = function (cmd, errorCode, errorInfo) {
            if(cmd=='longpolling' && errorCode==longPollingTimeOutErrorCode){//longpolling 返回60008错误可以视为正常,可以不上报
                return;
            }
            var eventId = CMD_EVENT_ID_MAP[cmd];
            if (eventId) {
                var reportTime = unixtime();
                var uniqKey = null;
                var msgCmdErrorCode = {
                    'Code': errorCode,
                    'ErrMsg': errorInfo
                };
                if (ctx.a2) {
                    uniqKey = ctx.a2.substring(0, 10) + "_" + reportTime + "_" + createRandom();
                } else if (ctx.userSig) {
                    uniqKey = ctx.userSig.substring(0, 10) + "_" + reportTime + "_" + createRandom();
                }
                
                if (uniqKey) {

                    var rptEvtItem = {
                        "UniqKey": uniqKey,
                        "EventId": eventId,
                        "ReportTime": reportTime,
                        "MsgCmdErrorCode": msgCmdErrorCode
                    };
                    
                    if(cmd=='login'){
                        var loginApiReportItems=[];
                        loginApiReportItems.push(rptEvtItem);
                        var loginReportOpt = {
                            "EvtItems": loginApiReportItems,
                            "MainVersion": SDK.VERSION,
                            "Version": "0"
                        };
                        proto_reportApiQuality(loginReportOpt, 
                            function (resp) {
                                loginApiReportItems=null;//
                            }, 
                            function (err) {
                                loginApiReportItems=null;//
                            }
                        );
                    }else{
                        apiReportItems.push(rptEvtItem);
                        if(apiReportItems.length>=maxApiReportItemCount){//累计一定条数再上报
                            var reportOpt = {
                                "EvtItems": apiReportItems,
                                "MainVersion": SDK.VERSION,
                                "Version": "0"
                            };
                            proto_reportApiQuality(reportOpt, 
                                function (resp) {
                                    apiReportItems=[];//清空
                                }, 
                                function (err) {
                                    apiReportItems=[];//清空
                                }
                            );
                        }
                    }
                    
                }
            }
        };
        
	// REST API calls
        //上线
	var proto_login = function(cbOk, cbErr) {
		ConnManager.apiCall(SRV_NAME.OPEN_IM,"login", {"State":"Online"}, 
                            function(loginResp){
                                if(loginResp.TinyId){
                                    ctx.tinyid=loginResp.TinyId;
                                }else{
                                    if(cbErr){
                                        cbErr(tool.getReturnError("TinyId is empty",-10));
                                        return;
                                    }
                                }
                                if(loginResp.A2Key){
                                    ctx.a2=loginResp.A2Key;
                                }else{
                                    if(cbErr){
                                        cbErr(tool.getReturnError("A2Key is empty",-11));
                                        return;
                                    }
                                }
                                var tag_list = [
                                    "Tag_Profile_IM_Nick"
                                ];
                                var options = {
                                    'From_Account': ctx.identifier,
                                    'To_Account': [ctx.identifier],
                                    'LastStandardSequence': 0,
                                    'TagList': tag_list
                                };
                                proto_getProfilePortrait(
                                    options,
                                    function (resp) {
                                        var nick, gender, allowType;
                                        if (resp.UserProfileItem && resp.UserProfileItem.length > 0) {
                                            for (var i in resp.UserProfileItem) {
                                                for (var j in resp.UserProfileItem[i].ProfileItem) {
                                                    switch (resp.UserProfileItem[i].ProfileItem[j].Tag) {
                                                        case 'Tag_Profile_IM_Nick':
                                                            nick = resp.UserProfileItem[i].ProfileItem[j].Value;
                                                            if(nick) ctx.identifierNick = nick;
                                                            break;
                                                    }
                                                }     
                                            }
                                        }
                                        if(cbOk) cbOk(ctx.identifierNick);//回传当前用户昵称
                                    },cbErr);
                            }
                        , cbErr);
	};
        //下线
	var proto_logout = function( cbOk, cbErr) {
            if (!checkLogin(cbErr,false)){//不带登录态
                clearSdk();
                if(cbOk) cbOk({
                        'ActionStatus':ACTION_STATUS.OK,
                        'ErrorCode':0,
                        'ErrorInfo':'logout success'
                    });
                    return;
                }
		ConnManager.apiCall(SRV_NAME.OPEN_IM,"logout", {}, 
                        function(resp){
                            clearSdk();
                            if(cbOk) cbOk(resp);
                        }, 
                        cbErr);
	};
        //发送消息，包括私聊和群聊
	var proto_sendMsg = function(msg, cbOk, cbErr) {
		if (!checkLogin(cbErr,true)) return;
                var msgInfo = null;
                
                switch(msg.sess.type()){
                    case SESSION_TYPE.C2C:
                        msgInfo = {
                            'From_Account': ctx.identifier,
                            'To_Account': msg.sess.id().toString(),
                            'MsgTimeStamp': msg.time,
                            'MsgSeq': msg.seq,
                            'MsgRandom':msg.random,
                            'MsgBody': []
                        };
                        break;
                    case SESSION_TYPE.GROUP:
                        var subType=msg.getSubType();
                        msgInfo = {
                            'GroupId': msg.sess.id().toString(),
                            'From_Account': ctx.identifier,
                            'Random': msg.random,
                            'MsgBody': []
                        };
                        switch(subType){
                            case GROUP_MSG_SUB_TYPE.COMMON:
                                msgInfo.MsgPriority="COMMON";
                                break;
                            case GROUP_MSG_SUB_TYPE.REDPACKET:
                                msgInfo.MsgPriority="REDPACKET";
                                break;
                            case GROUP_MSG_SUB_TYPE.LOVEMSG:
                                msgInfo.MsgPriority="LOVEMSG";
                                break;
                            case GROUP_MSG_SUB_TYPE.TIP:
                                log.error("不能主动发送群提示消息,subType="+subType);
                                break;
                            default:
                                log.error("发送群消息时，出现未知子消息类型：subType="+subType);
                                return;
                                break;
                        };
                        break;
                    default:
                        break;
                }
		
		for (var i in msg.elems) {
			var elem = msg.elems[i];
                        var msgContent=null;
                        var msgType=elem.type;
                        switch(msgType){
                            case MSG_ELEMENT_TYPE.TEXT://文本
                                msgContent={'Text':elem.content.text};
                                break;
                            case MSG_ELEMENT_TYPE.FACE://表情
                                msgContent={'Index':elem.content.index,'Data':elem.content.data};
                                break;
                            case MSG_ELEMENT_TYPE.IMAGE://图片
                                var ImageInfoArray=[];
                                for(var j in elem.content.ImageInfoArray){
                                    ImageInfoArray.push(
                                        {
                                            'Type':elem.content.ImageInfoArray[j].type,
                                            'Size':elem.content.ImageInfoArray[j].size,
                                            'Width':elem.content.ImageInfoArray[j].width,
                                            'Height':elem.content.ImageInfoArray[j].height,
                                            'URL':elem.content.ImageInfoArray[j].url
                                        }
                                    );
                                }
                                msgContent={'UUID':elem.content.UUID,'ImageInfoArray':ImageInfoArray};
                                break;
                            case MSG_ELEMENT_TYPE.SOUND://
                                log.warn('web端暂不支持发送语音消息');
                                continue;
                                break;
                            case MSG_ELEMENT_TYPE.LOCATION://
                                log.warn('web端暂不支持发送地理位置消息');
                                continue;
                                break;
                            case MSG_ELEMENT_TYPE.FILE://
                                log.warn('web端暂不支持发送语音消息');
                                continue;
                                break;
                            case MSG_ELEMENT_TYPE.CUSTOM://
                                msgContent={'Data':elem.content.data,'Desc':elem.content.desc,'Ext':elem.content.ext};
                                msgType=MSG_ELEMENT_TYPE.CUSTOM;
                                break;
                            default :
                                log.warn('web端暂不支持发送'+elem.type+'消息');
                                continue;
                                break;
                        }
			msgInfo.MsgBody.push({'MsgType':msgType,'MsgContent':msgContent});
		}
                if(msg.sess.type()==SESSION_TYPE.C2C){//私聊
                    ConnManager.apiCall(SRV_NAME.OPEN_IM,"sendmsg", msgInfo, cbOk, cbErr);
                }else if(msg.sess.type()==SESSION_TYPE.GROUP){//群聊
                    ConnManager.apiCall(SRV_NAME.GROUP,"send_group_msg", msgInfo, cbOk, cbErr);
                } 
	};
        //长轮询接口
        var proto_longPolling = function(options,cbOk, cbErr) {
		if (!checkLogin(cbErr,true)) return;
		ConnManager.apiCall(SRV_NAME.OPEN_IM,"longpolling", options, cbOk, cbErr,longPollingDefaultTimeOut,true);
	};
        
        //长轮询接口(拉取直播聊天室新消息)
        var proto_bigGroupLongPolling = function(options,cbOk, cbErr,timeout) {
                ConnManager.apiCall(SRV_NAME.BIG_GROUP_LONG_POLLING,"get_msg", options, cbOk, cbErr,timeout);
	};
        
        //拉取未读c2c消息接口
        var proto_getMsgs = function(cookie, syncFlag,cbOk, cbErr) {    
		if (!checkLogin(cbErr,true)) return;
		ConnManager.apiCall(SRV_NAME.OPEN_IM,"getmsg", {'Cookie':cookie,'SyncFlag':syncFlag}, 
                                        function(resp){
                                            
                                            if(resp.MsgList && resp.MsgList.length){
                                                for(var i in resp.MsgList){
                                                     tempC2CMsgList.push(resp.MsgList[i]);
                                                } 
                                            }
                                            if(resp.SyncFlag==1){
                                                proto_getMsgs(resp.Cookie,resp.SyncFlag,cbOk,cbErr);
                                            }else{
                                                resp.MsgList=tempC2CMsgList;
                                                tempC2CMsgList=[];
                                                if (cbOk) cbOk(resp);
                                            }
                                        },
                                        cbErr);
	};
        //C2C消息已读上报接口
        var proto_c2CMsgReaded = function(cookie, c2CMsgReadedItem,cbOk, cbErr) {
		if (!checkLogin(cbErr,true)) return;
                var tmpC2CMsgReadedItem=[];
                for(var i in c2CMsgReadedItem){
                    var item={
                        'To_Account':c2CMsgReadedItem[i].toAccount,
                        'LastedMsgTime':c2CMsgReadedItem[i].lastedMsgTime
                    };
                    tmpC2CMsgReadedItem.push(item);
                }
		ConnManager.apiCall(SRV_NAME.OPEN_IM,"msgreaded", {C2CMsgReaded:{'Cookie':cookie,'C2CMsgReadedItem':tmpC2CMsgReadedItem}}, cbOk, cbErr);
	};
        
        //删除c2c消息
        var proto_deleteC2CMsg = function(options,cbOk, cbErr) {
		if (!checkLogin(cbErr,true)) return;
                
		ConnManager.apiCall(SRV_NAME.OPEN_IM,"deletemsg",options , 
                                   cbOk, cbErr);
	};
        
        //拉取c2c历史消息接口
        var proto_getC2CHistoryMsgs = function(options,cbOk, cbErr) {    
		if (!checkLogin(cbErr,true)) return;
		ConnManager.apiCall(SRV_NAME.OPEN_IM,"getroammsg", options, 
                                        function(resp){
                                            var reqMsgCount=options.MaxCnt;
                                            var complete=resp.Complete;
                                            var rspMsgCount=resp.MaxCnt;
                                            var msgKey=resp.MsgKey;
                                            var lastMsgTime=resp.LastMsgTime;
                                            
                                            if(resp.MsgList && resp.MsgList.length){
                                                for(var i in resp.MsgList){
                                                     tempC2CHistoryMsgList.push(resp.MsgList[i]);
                                                }
                                            }
                                            var netxOptions=null;
                                            if(complete==0){//还有历史消息可拉取
                                                if(rspMsgCount<reqMsgCount){
                                                    netxOptions={
                                                        'Peer_Account':options.Peer_Account,
                                                        'MaxCnt':reqMsgCount-rspMsgCount,
                                                        'LastMsgTime':lastMsgTime,
                                                        'MsgKey':msgKey
                                                    };
                                                }
                                            }
                                           
                                            if(netxOptions){//继续拉取                                          
                                                proto_getC2CHistoryMsgs(netxOptions,cbOk,cbErr);
                                            }else{
                                                resp.MsgList=tempC2CHistoryMsgList;
                                                tempC2CHistoryMsgList=[];
                                                if (cbOk) cbOk(resp);
                                            }
                                        },
                                        cbErr);
	};
        
        //群组接口
        //创建群组
        //协议参考：https://www.qcloud.com/doc/product/269/1615
        var proto_createGroup = function(options,cbOk, cbErr) {
		if (!checkLogin(cbErr,true)) return;
                var opt={
                    //必填	群组形态，包括Public（公开群），Private（私密群），ChatRoom（聊天室），AVChatRoom（互动直播聊天室）。
                    'Type':options.Type,
                    //必填	群名称，最长30字节。
                    'Name':options.Name
                };
                var member_list=[];
                
                //Array	选填	初始群成员列表，最多500个。成员信息字段详情参见：群成员资料。
                for(var i=0;i<options.MemberList.length;i++){
                    member_list.push({'Member_Account':options.MemberList[i]})
                }
                opt.MemberList=member_list;
                //选填	为了使得群组ID更加简单，便于记忆传播，腾讯云支持APP在通过REST API创建群组时自定义群组ID。详情参见：自定义群组ID。
                if(options.GroupId){
                    opt.GroupId=options.GroupId;
                }
                //选填	群主id，自动添加到群成员中。如果不填，群没有群主。
                if(options.Owner_Account){
                    opt.Owner_Account=options.Owner_Account;
                }
                //选填	群简介，最长240字节。
                if(options.Introduction){
                    opt.Introduction=options.Introduction;
                }
                //选填	群公告，最长300字节。
                if(options.Notification){
                    opt.Notification=options.Notification;
                }
                //选填	最大群成员数量，最大为10000，不填默认为2000个。
                if(options.MaxMemberCount){
                    opt.MaxMemberCount=options.MaxMemberCount;
                }
                //选填	申请加群处理方式。包含FreeAccess（自由加入），NeedPermission（需要验证），DisableApply（禁止加群），不填默认为NeedPermission（需要验证）。
                if(options.ApplyJoinOption){//
                    opt.ApplyJoinOption=options.ApplyJoinOption;
                }
                //Array	选填	群组维度的自定义字段，默认情况是没有的，需要开通，详情参见：自定义字段。
                if(options.AppDefinedData){
                    opt.AppDefinedData=options.AppDefinedData;
                }
                //选填	群头像URL，最长100字节。
                if(options.FaceUrl){
                    opt.FaceUrl=options.FaceUrl;
                }
		ConnManager.apiCall(SRV_NAME.GROUP,"create_group", opt, 
                                   cbOk, cbErr);
	};
        
        //创建群组-高级接口
        //协议参考：https://www.qcloud.com/doc/product/269/1615
        var proto_createGroupHigh = function(options,cbOk, cbErr) {
		if (!checkLogin(cbErr,true)) return;
		ConnManager.apiCall(SRV_NAME.GROUP,"create_group", options, 
                                   cbOk, cbErr);
	};
        
        //修改群组基本资料
        //协议参考：https://www.qcloud.com/doc/product/269/1620
        var proto_modifyGroupBaseInfo = function(options,cbOk, cbErr) {
		if (!checkLogin(cbErr,true)) return;
                
		ConnManager.apiCall(SRV_NAME.GROUP,"modify_group_base_info", options, 
                                   cbOk, cbErr);
	};
        
        //申请加群
        var proto_applyJoinGroup = function(options,cbOk, cbErr) {
		if (!checkLogin(cbErr,true)) return;
                
		ConnManager.apiCall(SRV_NAME.GROUP,"apply_join_group", {
                                                'GroupId':options.GroupId,
                                                'ApplyMsg':options.ApplyMsg,
                                                'UserDefinedField':options.UserDefinedField
                                              }, 
                                   cbOk, cbErr);
	};
        
        //申请加入大群
        var proto_applyJoinBigGroup = function(options,cbOk, cbErr) {
                var srvName;
		if (!checkLogin(cbErr,false)){//未登录
                    srvName=SRV_NAME.BIG_GROUP;
                }else{//已登录
                    srvName=SRV_NAME.GROUP;
                }
		ConnManager.apiCall(srvName,"apply_join_group", {
                                                'GroupId':options.GroupId,
                                                'ApplyMsg':options.ApplyMsg,
                                                'UserDefinedField':options.UserDefinedField
                                              }, 
                                   function(resp){
                                       if(resp.JoinedStatus && resp.JoinedStatus=='JoinedSuccess'){
                                           if(resp.LongPollingKey){
                                               MsgManager.setBigGroupLongPollingOn(true);//开启长轮询
                                               MsgManager.setBigGroupLongPollingKey(resp.LongPollingKey);//更新大群长轮询key
                                               MsgManager.setBigGroupLongPollingMsgMap(options.GroupId,0);//收到的群消息置0
                                               MsgManager.bigGroupLongPolling();//开启长轮询
                                           }else{//没有返回LongPollingKey，说明申请加的群不是直播聊天室(AVChatRoom)
                                               cbErr && cbErr(tool.getReturnError("The type of group is not AVChatRoom: groupid="+options.GroupId,-12));
                                               return;
                                           }
                                       }
                                       if(cbOk) cbOk(resp);
                                   }
                                   , function(err){

                                        if(cbErr) cbErr(err);
                                   });
	};
        
        //处理加群申请(同意或拒绝)
        var proto_handleApplyJoinGroupPendency = function(options,cbOk, cbErr) {
		if (!checkLogin(cbErr,true)) return;
                
		ConnManager.apiCall(SRV_NAME.GROUP,"handle_apply_join_group", {
                                                'GroupId':options.GroupId,
                                                'Applicant_Account':options.Applicant_Account,
                                                'HandleMsg':options.HandleMsg,
                                                'Authentication':options.Authentication,
                                                'MsgKey':options.MsgKey,
                                                'ApprovalMsg':options.ApprovalMsg,
                                                'UserDefinedField':options.UserDefinedField
                                              }, 
                                   cbOk, 
                                   function(err){
                                       if(err.ErrorCode==10024){//apply has be handled
                                           if(cbOk){
                                               var resp={
                                                    'ActionStatus':ACTION_STATUS.OK,
                                                    'ErrorCode':0,
                                                    'ErrorInfo':'该申请已经被处理过'
                                                };
                                               cbOk(resp);
                                           } 
                                       }else{
                                           if(cbErr) cbErr(err);
                                       }
                                   }
                );
	};
        
        //主动退群
        var proto_quitGroup = function(options,cbOk, cbErr) {
		if (!checkLogin(cbErr,true)) return;
                
		ConnManager.apiCall(SRV_NAME.GROUP,"quit_group", {
                                                'GroupId':options.GroupId
                                              }, 
                                   cbOk, cbErr);
	};
        
        //退出大群
        var proto_quitBigGroup = function(options,cbOk, cbErr) {
                var srvName;
		if (!checkLogin(cbErr,false)){//未登录
                    srvName=SRV_NAME.BIG_GROUP;
                }else{//已登录
                    srvName=SRV_NAME.GROUP;
                }
		ConnManager.apiCall(srvName,"quit_group", 
                                            {'GroupId':options.GroupId}, 
                                            function(resp){
                                                //重置当前再请求中的ajax
                                                //clearXmlHttpObjMap();
                                                //退出大群成功之后需要重置长轮询信息
                                                MsgManager.resetBigGroupLongPollingInfo();
                                                if(cbOk) cbOk(resp);
                                            },
                                            cbErr);
	};
        
        //获取群组公开资料
        var proto_getGroupPublicInfo = function(options,cbOk, cbErr) {
		if (!checkLogin(cbErr,true)) return;
                
		ConnManager.apiCall(SRV_NAME.GROUP,"get_group_public_info", {
                                                'GroupIdList':options.GroupIdList,
                                                'ResponseFilter':{
                                                    'GroupBasePublicInfoFilter':options.GroupBasePublicInfoFilter
                                                } 
                                              }, 
                                   function(resp){
                                       resp.ErrorInfo='';
                                       if(resp.GroupInfo){
                                           for(var i in resp.GroupInfo){
                                               var errorCode=resp.GroupInfo[i].ErrorCode;
                                               if(errorCode>0){
                                                   resp.ActionStatus=ACTION_STATUS.FAIL;
                                                   resp.GroupInfo[i].ErrorInfo="["+errorCode+"]"+resp.GroupInfo[i].ErrorInfo;
                                                   resp.ErrorInfo+=resp.GroupInfo[i].ErrorInfo+'\n';
                                               }
                                           }
                                       }
                                       if(resp.ActionStatus==ACTION_STATUS.FAIL){
                                           if(cbErr){
                                               cbErr(resp);
                                           }
                                       }else if(cbOk){
                                           cbOk(resp);
                                       }
                                       
                                   },
                                   cbErr);
	};
        
        //获取群组详细资料--高级
        //请求协议参考：https://www.qcloud.com/doc/product/269/1616
        var proto_getGroupInfo = function(options,cbOk, cbErr) {
		if (!checkLogin(cbErr,true)) return;
                
                var opt={
                    'GroupIdList':options.GroupIdList,
                    'ResponseFilter':{
                        'GroupBaseInfoFilter':options.GroupBaseInfoFilter,
                        'MemberInfoFilter':options.MemberInfoFilter
                    } 
                };
                if(options.AppDefinedDataFilter_Group){
                    opt.ResponseFilter.AppDefinedDataFilter_Group=options.AppDefinedDataFilter_Group;
                }
                if(options.AppDefinedDataFilter_GroupMember){
                    opt.ResponseFilter.AppDefinedDataFilter_GroupMember=options.AppDefinedDataFilter_GroupMember;
                }
		ConnManager.apiCall(SRV_NAME.GROUP,"get_group_info", opt, 
                                   cbOk, cbErr);
	};
        
        //获取群组成员-高级接口
        //协议参考：https://www.qcloud.com/doc/product/269/1617
        var proto_getGroupMemberInfo = function(options,cbOk, cbErr) {
		if (!checkLogin(cbErr,true)) return;
                
		ConnManager.apiCall(SRV_NAME.GROUP,"get_group_member_info", {
                                                'GroupId':options.GroupId,
                                                'Offset':options.Offset,
                                                'Limit':options.Limit,
                                                'MemberInfoFilter':options.MemberInfoFilter,
                                                'MemberRoleFilter':options.MemberRoleFilter,
                                                'AppDefinedDataFilter_GroupMember':options.AppDefinedDataFilter_GroupMember
                                              }, 
                                   cbOk, cbErr);
	};
        
        
        //增加群组成员
        //协议参考：https://www.qcloud.com/doc/product/269/1621
        var proto_addGroupMember = function(options,cbOk, cbErr) {
		if (!checkLogin(cbErr,true)) return;
                
		ConnManager.apiCall(SRV_NAME.GROUP,"add_group_member", {
                                                'GroupId':options.GroupId,
                                                'Silence':options.Silence,
                                                'MemberList':options.MemberList 
                                              }, 
                                   cbOk, cbErr);
	};
        //修改群组成员资料
        //协议参考：https://www.qcloud.com/doc/product/269/1623
        var proto_modifyGroupMember = function(options,cbOk, cbErr) {
		if (!checkLogin(cbErr,true)) return;
                var opt={};
                if(options.GroupId){
                    opt.GroupId=options.GroupId;
                }
                if(options.Member_Account){
                    opt.Member_Account=options.Member_Account;
                }
                //Admin或者Member
                if(options.Role){
                    opt.Role=options.Role;
                }
                // AcceptAndNotify代表解收并提示消息，Discard代表不接收也不提示消息，AcceptNotNotify代表接收消息但不提示
                if(options.MsgFlag){
                    opt.MsgFlag=options.MsgFlag;
                }
                if(options.ShutUpTime){//禁言时间
                    opt.ShutUpTime=options.ShutUpTime;
                }
                if(options.NameCard){//群名片,最大不超过50个字节
                    opt.NameCard=options.NameCard;
                }
                if(options.AppMemberDefinedData){//群成员维度的自定义字段，默认情况是没有的，需要开通
                    opt.AppMemberDefinedData=options.AppMemberDefinedData;
                }
		ConnManager.apiCall(SRV_NAME.GROUP,"modify_group_member_info", opt, 
                                   cbOk, cbErr);
	};
        //删除群组成员
        //协议参考：https://www.qcloud.com/doc/product/269/1622
        var proto_deleteGroupMember = function(options,cbOk, cbErr) {
		if (!checkLogin(cbErr,true)) return;
                
		ConnManager.apiCall(SRV_NAME.GROUP,"delete_group_member", {
                                                'GroupId':options.GroupId,
                                                'Silence':options.Silence,
                                                'MemberToDel_Account':options.MemberToDel_Account,
                                                'Reason':options.Reason
                                              }, 
                                   cbOk, cbErr);
	};
        //解散群组
        //协议参考：https://www.qcloud.com/doc/product/269/1624
        var proto_destroyGroup = function(options,cbOk, cbErr) {
		if (!checkLogin(cbErr,true)) return;
                
		ConnManager.apiCall(SRV_NAME.GROUP,"destroy_group", {
                                                'GroupId':options.GroupId
                                              }, 
                                   cbOk, cbErr);
	};
        //获取用户所加入的群组-高级接口
        //协议参考：https://www.qcloud.com/doc/product/269/1625
        var proto_getJoinedGroupListHigh = function(options,cbOk, cbErr) {
		if (!checkLogin(cbErr,true)) return;
                
		ConnManager.apiCall(SRV_NAME.GROUP,"get_joined_group_list", {
                                                'Member_Account':options.Member_Account,
                                                'Limit':options.Limit,
                                                'Offset':options.Offset,
                                                'GroupType':options.GroupType,
                                                'ResponseFilter':{
                                                    'GroupBaseInfoFilter':options.GroupBaseInfoFilter,
                                                    'SelfInfoFilter':options.SelfInfoFilter
                                                }
                                              }, 
                                   cbOk, cbErr);
	};
        //查询一组UserId在群中的身份
        //协议参考：https://www.qcloud.com/doc/product/269/1626
        var proto_getRoleInGroup = function(options,cbOk, cbErr) {
		if (!checkLogin(cbErr,true)) return;
                
		ConnManager.apiCall(SRV_NAME.GROUP,"get_role_in_group", {
                                                'GroupId':options.GroupId,
                                                'User_Account':options.User_Account
                                              }, 
                                   cbOk, cbErr);
	};
        //设置取消成员禁言时间
        //协议参考：https://www.qcloud.com/doc/product/269/1627
        var proto_forbidSendMsg = function(options,cbOk, cbErr) {
		if (!checkLogin(cbErr,true)) return;
                
		ConnManager.apiCall(SRV_NAME.GROUP,"forbid_send_msg", {
                                                'GroupId':options.GroupId,
                                                'Members_Account':options.Members_Account,
                                                'ShutUpTime':options.ShutUpTime//单位为秒，为0时表示取消禁言
                                              }, 
                                   cbOk, cbErr);
	};
        
        //发送自定义群系统通知
        var proto_sendCustomGroupNotify = function(options,cbOk, cbErr) {
		if (!checkLogin(cbErr,true)) return;
		ConnManager.apiCall(SRV_NAME.GROUP,"send_group_system_notification", options, 
                                   cbOk, cbErr);
	};
        
        //拉取群消息接口
        var proto_getGroupMsgs = function(options,cbOk, cbErr) {
		if (!checkLogin(cbErr,true)) return;
		ConnManager.apiCall(SRV_NAME.GROUP,"group_msg_get", {
                                              "GroupId":options.GroupId,
                                              "ReqMsgSeq":options.ReqMsgSeq,
                                              "ReqMsgNumber":options.ReqMsgNumber
                                          }, 
                                    cbOk, cbErr);
	};
        //群消息已读上报接口
        var proto_groupMsgReaded = function(options,cbOk, cbErr) {
		if (!checkLogin(cbErr,true)) return;
		ConnManager.apiCall(SRV_NAME.GROUP,"msg_read_report", {
                                              'GroupId':options.GroupId,
                                              'MsgReadedSeq':options.MsgReadedSeq
                                          }, 
                                    cbOk, cbErr);
	};
        //end
        
        //好友接口
        //处理好友接口返回的错误码
        var convertErrorEn2ZhFriend=function(resp){
                        var errorAccount=[];
                        if (resp.Fail_Account && resp.Fail_Account.length){
                            errorAccount = resp.Fail_Account;
                        }
                        if (resp.Invalid_Account && resp.Invalid_Account.length){
                            for (var k in resp.Invalid_Account){
                                errorAccount.push(resp.Invalid_Account[k]);
                            }
                        }
                        if (errorAccount.length){
                            resp.ActionStatus=ACTION_STATUS.FAIL;
                            resp.ErrorCode=ERROR_CODE_CUSTOM;
                            resp.ErrorInfo='';
                            for (var i in errorAccount){
                                var failCount = errorAccount[i];
                                for (var j in resp.ResultItem){
                                    if (resp.ResultItem[j].To_Account == failCount){
                                        
                                        var resultCode = resp.ResultItem[j].ResultCode;
                                        resp.ResultItem[j].ResultInfo = "[" + resultCode + "]" + resp.ResultItem[j].ResultInfo;
                                        resp.ErrorInfo+=resp.ResultItem[j].ResultInfo+"\n";
                                        break;
                                    }
                                }
                            }
                        }
                        return resp;
        };
        //添加好友
        var proto_applyAddFriend = function(options,cbOk, cbErr) {
		if (!checkLogin(cbErr,true)) return;
		ConnManager.apiCall(SRV_NAME.FRIEND,"friend_add", {
                                              'From_Account':ctx.identifier,
                                              'AddFriendItem':options.AddFriendItem
                                          }, 
                                    function(resp){
                                        var newResp=convertErrorEn2ZhFriend(resp);
                                        if(newResp.ActionStatus==ACTION_STATUS.FAIL ){
                                            if(cbErr) cbErr(newResp);
                                        }else if(cbOk) {
                                            cbOk(newResp);
                                        }
                                    }, cbErr);
	};
        //删除好友
        var proto_deleteFriend = function(options,cbOk, cbErr) {
		if (!checkLogin(cbErr,true)) return;
		ConnManager.apiCall(SRV_NAME.FRIEND,"friend_delete", {
                                              'From_Account':ctx.identifier,
                                              'To_Account':options.To_Account,
                                              'DeleteType':options.DeleteType
                                          }, 
                                    function(resp){
                                        var newResp=convertErrorEn2ZhFriend(resp);
                                        if(newResp.ActionStatus==ACTION_STATUS.FAIL ){
                                            if(cbErr) cbErr(newResp);
                                        }else if(cbOk) {
                                            cbOk(newResp);
                                        }
                                    }, cbErr);
	};
        //获取好友申请
        var proto_getPendency = function(options,cbOk, cbErr) {
		if (!checkLogin(cbErr,true)) return;
		ConnManager.apiCall(SRV_NAME.FRIEND,"pendency_get", {
                                              "From_Account":ctx.identifier,
                                              "PendencyType":options.PendencyType,
                                              "StartTime":options.StartTime,
                                              "MaxLimited":options.MaxLimited,
                                              "LastSequence":options.LastSequence
                                          }, 
                                    cbOk, cbErr);
	};
        //删除好友申请
        var proto_deletePendency = function(options,cbOk, cbErr) {
		if (!checkLogin(cbErr,true)) return;
		ConnManager.apiCall(SRV_NAME.FRIEND,"pendency_delete", {
                                              "From_Account":ctx.identifier,
                                              "PendencyType":options.PendencyType,
                                              "To_Account":options.To_Account
                                              
                                          }, 
                                    function(resp){
                                        var newResp=convertErrorEn2ZhFriend(resp);
                                        if(newResp.ActionStatus==ACTION_STATUS.FAIL ){
                                            if(cbErr) cbErr(newResp);
                                        }else if(cbOk) {
                                            cbOk(newResp);
                                        }
                                    }, cbErr);
	};
        //处理好友申请
        var proto_responseFriend = function(options,cbOk, cbErr) {
		if (!checkLogin(cbErr,true)) return;
		ConnManager.apiCall(SRV_NAME.FRIEND,"friend_response", {
                                              'From_Account':ctx.identifier,
                                              'ResponseFriendItem':options.ResponseFriendItem
                                          }, 
                                    function(resp){
                                        var newResp=convertErrorEn2ZhFriend(resp);
                                        if(newResp.ActionStatus==ACTION_STATUS.FAIL ){
                                            if(cbErr) cbErr(newResp);
                                        }else if(cbOk) {
                                            cbOk(newResp);
                                        }
                                    }, cbErr);
	};
        //我的好友
        var proto_getAllFriend = function(options,cbOk, cbErr) {
		if (!checkLogin(cbErr,true)) return;
		ConnManager.apiCall(SRV_NAME.FRIEND,"friend_get_all", {
                                              'From_Account':ctx.identifier,
                                              'TimeStamp':options.TimeStamp,
                                              'StartIndex':options.StartIndex,
                                              'GetCount':options.GetCount,
                                              'LastStandardSequence':options.LastStandardSequence,
                                              'TagList':options.TagList
                                          }, 
                                    cbOk, cbErr);
	};
        
        //资料接口
        //查看个人资料
        var proto_getProfilePortrait = function(options,cbOk, cbErr) {
		if (!checkLogin(cbErr,true)) return;
		ConnManager.apiCall(SRV_NAME.PROFILE,"portrait_get", {
                                              'From_Account':ctx.identifier,
                                              'To_Account':options.To_Account,
                                              'LastStandardSequence':options.LastStandardSequence,
                                              'TagList':options.TagList
                                          }, 
                                    function(resp){
                                        var errorAccount=[];
                                        if(resp.Fail_Account && resp.Fail_Account.length){
                                            errorAccount=resp.Fail_Account;
                                        }
                                        if(resp.Invalid_Account && resp.Invalid_Account.length){
                                            for(var k in resp.Invalid_Account){
                                                errorAccount.push(resp.Invalid_Account[k]);
                                            } 
                                        }
                                        if(errorAccount.length){
                                            resp.ActionStatus=ACTION_STATUS.FAIL;
                                            resp.ErrorCode=ERROR_CODE_CUSTOM;
                                            resp.ErrorInfo='';
                                            for(var i in errorAccount){
                                                var failCount=errorAccount[i];
                                                for(var j in resp.UserProfileItem){
                                                    if(resp.UserProfileItem[j].To_Account==failCount){
                                                        var resultCode=resp.UserProfileItem[j].ResultCode;
                                                        resp.UserProfileItem[j].ResultInfo = "[" + resultCode + "]" + resp.UserProfileItem[j].ResultInfo;
                                                        resp.ErrorInfo+="账号:"+failCount+","+resp.UserProfileItem[j].ResultInfo+"\n";
                                                        break;
                                                    }
                                                }
                                            }
                                        }
                                        if(resp.ActionStatus==ACTION_STATUS.FAIL ){
                                            if(cbErr) cbErr(resp);
                                        }else if(cbOk) {
                                            cbOk(resp);
                                        }
                                    }, 
                                    cbErr);
	};
        
        //设置个人资料
        var proto_setProfilePortrait = function(options,cbOk, cbErr) {
		if (!checkLogin(cbErr,true)) return;
		ConnManager.apiCall(SRV_NAME.PROFILE,"portrait_set", 
                                          {
                                              'From_Account':ctx.identifier,
                                              'ProfileItem':options.ProfileItem
                                          }, 
                                          function(resp){
                                              for(var i in options.ProfileItem){
                                                  var profile=options.ProfileItem[i];
                                                  if(profile.Tag=='Tag_Profile_IM_Nick'){
                                                      ctx.identifierNick=profile.Value;//更新昵称
                                                      break;
                                                  }
                                              }
                                              if(cbOk) cbOk(resp);
                                          }
                                          , cbErr);
	};
        
        //增加黑名单
        var proto_addBlackList = function(options,cbOk, cbErr) {
		if (!checkLogin(cbErr,true)) return;
		ConnManager.apiCall(SRV_NAME.FRIEND,"black_list_add", {
                                              'From_Account':ctx.identifier,
                                              'To_Account':options.To_Account
                                          }, 
                                    function(resp){
                                        var newResp=convertErrorEn2ZhFriend(resp);
                                        if(newResp.ActionStatus==ACTION_STATUS.FAIL ){
                                            if(cbErr) cbErr(newResp);
                                        }else if(cbOk) {
                                            cbOk(newResp);
                                        }
                                    }, cbErr);
	};
        
        //删除黑名单
        var proto_deleteBlackList = function(options,cbOk, cbErr) {
		if (!checkLogin(cbErr,true)) return;
		ConnManager.apiCall(SRV_NAME.FRIEND,"black_list_delete", {
                                              'From_Account':ctx.identifier,
                                              'To_Account':options.To_Account
                                          }, 
                                    function(resp){
                                        var newResp=convertErrorEn2ZhFriend(resp);
                                        if(newResp.ActionStatus==ACTION_STATUS.FAIL ){
                                            if(cbErr) cbErr(newResp);
                                        }else if(cbOk) {
                                            cbOk(newResp);
                                        }
                                    }, cbErr);
	};
        
        //我的黑名单
        var proto_getBlackList = function(options,cbOk, cbErr) {
		if (!checkLogin(cbErr,true)) return;
		ConnManager.apiCall(SRV_NAME.FRIEND,"black_list_get", {
                                              'From_Account':ctx.identifier,
                                              'StartIndex':options.StartIndex,
                                              'MaxLimited':options.MaxLimited,
                                              'LastSequence':options.LastSequence
                                          }, 
                                    cbOk, cbErr);
	};
        
        //上传图片
        var proto_uploadPic = function(options,cbOk, cbErr) {
		if (!checkLogin(cbErr,true)) return;
                if(isAccessFormalEnv()){
                    cmdName='pic_up';
                }else{
                    cmdName='pic_up_test';
                }
		ConnManager.apiCall(SRV_NAME.PIC,cmdName, {
                                              'App_Version':SDK.APPID,
                                              'From_Account':ctx.identifier,
                                              'To_Account':options.To_Account,
                                              'Seq':options.Seq,
                                              'Timestamp':options.Timestamp,
                                              'Random':options.Random,
                                              'File_Str_Md5':options.File_Str_Md5,
                                              'File_Size':options.File_Size,
                                              'Busi_Id':options.Busi_Id,
                                              'PkgFlag':options.PkgFlag,
                                              'Slice_Offset':options.Slice_Offset,
                                              'Slice_Size':options.Slice_Size,
                                              'Slice_Data':options.Slice_Data
                                          }, 
                                    cbOk, cbErr);
	};
        
        //获取语音和文件下载IP和authkey
        var proto_getIpAndAuthkey = function(cbOk, cbErr) {
		if (!checkLogin(cbErr,true)) return;
		ConnManager.apiCall(SRV_NAME.OPEN_IM,"authkey", {}, cbOk, cbErr);
	};
        
        //接口质量上报
        var proto_reportApiQuality = function(options,cbOk, cbErr) {
		if (!checkLogin(cbErr,true)) return;
		ConnManager.apiCall(SRV_NAME.IM_OPEN_STAT,"web_report", options,cbOk, cbErr);
	};
        
        //end
        initBrowserInfo();
	// singleton object ConnManager     
	var ConnManager = lowerBR == false 
        ? new function() {
		var onConnCallback = null;        //回调函数
		this.init = function(onConnNotify,cbOk,cbErr) {
		   if(onConnNotify) onConnCallback=onConnNotify;
		};
                this.callBack=function(info){
                    if(onConnCallback) onConnCallback(info);
                };
                this.clear=function(){
                    onConnCallback=null;
                };
                //请求后台服务接口
		this.apiCall = function(type,cmd, data, cbOk, cbErr,timeout,isLongPolling) {
                        //封装后台服务接口地址
                        var url=getApiUrl(type,cmd,cbOk, cbErr);
                        if(url==false) return;
                        //发起ajax请求
			ajaxRequestJson("POST", url, data, timeout,isLongPolling,function(resp) {
                                var errorCode=null,tempErrorInfo='';
                                var info="\n request url: \n"+url+"\n request body: \n"+JSON.stringify(data)+"\n response: \n"+JSON.stringify(resp);
                                //成功
				if (resp.ActionStatus == ACTION_STATUS.OK) {
                                        log.info("["+type+"]["+cmd+"]success: "+info);
                                        if (cbOk) cbOk(resp);//回调
                                        errorCode=0;
                                        tempErrorInfo='';
				} else {
                                        errorCode=resp.ErrorCode;
                                        tempErrorInfo=resp.ErrorInfo;
                                        //报错
					if (cbErr){
                                            resp.SrcErrorInfo=resp.ErrorInfo;
                                            resp.ErrorInfo="["+type+"]["+cmd+"]failed: "+info;
                                            if(cmd!='longpolling' || resp.ErrorCode!=longPollingTimeOutErrorCode){
                                                log.error(resp.ErrorInfo);
                                            }
                                            cbErr(resp);
                                        } 
				}
                                reportApiQuality(cmd,errorCode,tempErrorInfo);//接口质量上报
			}, function(err){
                            cbErr && cbErr(err);
                            reportApiQuality(cmd,err.ErrorCode,err.ErrorInfo);//接口质量上报
                        });
		};
	} 
        :new function () {
                var onConnCallback = null;        //回调函数
		this.init = function(onConnNotify,cbOk,cbErr) {
			if(onConnNotify) onConnCallback=onConnNotify;
		};
                this.callBack=function(info){
                    if(onConnCallback) onConnCallback(info);
                };
                this.clear=function(){
                    onConnCallback=null;
                };
                //请求后台服务接口
		this.apiCall = function(type,cmd, data, cbOk, cbErr,timeout,isLongPolling) {
                        //封装后台服务接口地址
                        var url=getApiUrl(type,cmd,cbOk, cbErr);
                        if(url==false) return;
                        //发起jsonp请求
                        var reqId = jsonpRequestId++,
                        cbkey = 'jsonpcallback', // the 'callback' key
                        cbval = 'jsonpRequest' + reqId, // the 'callback' value
                        script = document.createElement('script'),
                        loaded = 0;
                        
                        window[cbval] = jsonpCallback;
                        script.type = 'text/javascript';
                        url=url+"&"+cbkey+"="+cbval+"&jsonpbody="+encodeURIComponent(JSON.stringify(data));
                        script.src = url;
                        script.async = true;
                        
                        if (typeof script.onreadystatechange !== 'undefined') {
                            // need this for IE due to out-of-order onreadystatechange(), binding script
                            // execution to an event listener gives us control over when the script
                            // is executed. See http://jaubourg.net/2010/07/loading-script-as-onclick-handler-of.html
                            script.event = 'onclick';
                            script.htmlFor = script.id = '_jsonpRequest_' + reqId;
                        }
                        
                        script.onload = script.onreadystatechange = function () {
                            if ((this.readyState && this.readyState!== 'complete' && this.readyState!== 'loaded') || loaded) {
                                return false;
                            }
                            script.onload = script.onreadystatechange = null;
                            script.onclick && script.onclick();
                            // Call the user callback with the last value stored and clean up values and scripts.
                            var resp=jsonpLastRspData;
                            var info="\n request url: \n"+url+"\n request body: \n"+JSON.stringify(data)+"\n response: \n"+JSON.stringify(resp);
                            if (resp.ActionStatus == ACTION_STATUS.OK){
                                log.info("["+type+"]["+cmd+"]success: "+info);
                                cbOk && cbOk(resp);
                            }else{
                                resp.ErrorInfo="["+type+"]["+cmd+"]failed "+info;
                                if(cmd!='longpolling' || resp.ErrorCode!=longPollingTimeOutErrorCode){
                                    log.error(resp.ErrorInfo);
                                }else{
                                    log.warn("["+type+"]["+cmd+"]success: "+info);
                                }
                                cbErr && cbErr(resp);
                            }
                            jsonpLastRspData = undefined;
                            document.body.removeChild(script);
                            loaded = 1;
                        };
 
                        // Add the script to the DOM head
                        document.body.appendChild(script);
		};
        };
	// class Session
	var Session = function(type, id, name, icon, time,seq) {
		this._impl = {
			skey: Session.skey(type, id),
			type: type,
			id: id,
			name: name,
			icon: icon,
			unread: 0,//未读消息数
			isAutoRead: false,
			time: time >= 0 ? time : 0,
                        curMaxMsgSeq:seq >= 0 ? seq : 0,
			msgs: []
		};
	};
	Session.skey = function(type, id) {
		return type + id;
	};
	Session.prototype.type = function() {return this._impl.type;};
	Session.prototype.id = function() {return this._impl.id;};
	Session.prototype.name = function() {return this._impl.name;};
	Session.prototype.icon = function() {return this._impl.icon;};
	Session.prototype.unread = function() {return this._impl.unread;};
	Session.prototype.time = function() {return this._impl.time;};
	Session.prototype.curMaxMsgSeq = function() {return this._impl.curMaxMsgSeq;};
	Session.prototype.msgCount = function() {return this._impl.msgs.length;};
	Session.prototype.msg = function(index) {return this._impl.msgs[index];};
        
	Session.prototype._impl_addMsg = function(msg) {
		this._impl.msgs.push(msg);
		//if (!msg.isSend && msg.time > this._impl.time)
		if (msg.time > this._impl.time)
			this._impl.time = msg.time;
                //if (!msg.isSend && msg.seq > this._impl.curMaxMsgSeq)
                if (msg.seq > this._impl.curMaxMsgSeq)
			this._impl.curMaxMsgSeq = msg.seq;
                //自己发送的消息不计入未读数
		if (!msg.isSend && !this._impl.isAutoRead){
			this._impl.unread++;
                }
	};
        //class C2CMsgReadedItem
        var C2CMsgReadedItem=function(toAccount,lastedMsgTime){
            this.toAccount=toAccount;
            this.lastedMsgTime=lastedMsgTime;
        }
	// class Msg
	var Msg = function(sess, isSend, seq, random,time,fromAccount,subType,fromAccountNick) {
		this.sess = sess;
                this.subType = subType>=0 ? subType : 0;//消息类型,c2c消息时，type取值为0；group消息时，type取值0和1，0-普通群消息，1-群提示消息
                this.fromAccount = fromAccount;
                this.fromAccountNick=fromAccountNick ? fromAccountNick : fromAccount;
                this.isSend = Boolean(isSend);
		this.seq = seq >= 0 ? seq : nextSeq();
		this.random = random >= 0 ? random : createRandom();
		this.time = time >= 0 ? time : unixtime();
		this.elems = [];
	};
        Msg.prototype.getSession = function() {
		return this.sess;
	};
        
        Msg.prototype.getType = function() {
		return this.subType;
	};
        Msg.prototype.getSubType = function() {
		return this.subType;
	};
        Msg.prototype.getFromAccount = function() {
		return this.fromAccount;
	};
        Msg.prototype.getFromAccountNick = function() {
		return this.fromAccountNick;
	};
        Msg.prototype.getIsSend = function() {
		return this.isSend;
	};
        Msg.prototype.getSeq = function() {
		return this.seq;
	};
        Msg.prototype.getTime = function() {
		return this.time;
	};
        Msg.prototype.getRandom= function() {
		return this.random;
	};
        Msg.prototype.getElems= function() {
		return this.elems;
	};
        //文本
	Msg.prototype.addText = function(text) {
		this.addElem(new webim.Msg.Elem(MSG_ELEMENT_TYPE.TEXT, text));
	};
        //表情
	Msg.prototype.addFace = function(face) {
		this.addElem(new webim.Msg.Elem(MSG_ELEMENT_TYPE.FACE, face));
	};
        //图片
	Msg.prototype.addImage = function(image) {
		this.addElem(new webim.Msg.Elem(MSG_ELEMENT_TYPE.IMAGE, image));
	};
        //自定义
	Msg.prototype.addCustom = function(custom) {
		this.addElem(new webim.Msg.Elem(MSG_ELEMENT_TYPE.CUSTOM, custom));
	};
        
	Msg.prototype.addElem = function(elem) {
		this.elems.push(elem);
	};
	Msg.prototype.toHtml = function() {
		var html = "";
		for (var i in this.elems) {
			var elem = this.elems[i];
			html += elem.toHtml();
		}
                return html;
	};
	// class Msg.Elem
	Msg.Elem = function(type, value) {
		this.type = type;
		this.content = value;
	};
        Msg.Elem.prototype.getType = function() {
		return this.type;
	};
        Msg.Elem.prototype.getContent = function() {
		return this.content;
	};
	Msg.Elem.prototype.toHtml = function() {
		var html;
                html=this.content.toHtml();
		return html;
	};
        // class Msg.Elem.Text
		// 配合小直播demo扩展文本消息，text会是json格式
	Msg.Elem.Text = function(text) {
		var _json;
		//if(/^\{.*\}$/.test(text.replace(/[\r\n\s+]/g,""))){
		if(/^\{.*\}$/.test(text) || /^\{.*\}$/.test(text.replace(/[\r\n\s+]/g,""))){
			try{
				this.text = text;
				_json = JSON.parse(text);
				//console.log('Msg.Elem.Text' ,_json);
				this.data = _json;
				this.data.nickName = tool.xssFilter(_json.nickName);
				this.data.msg = tool.xssFilter(_json.msg);
				this.isAppMsg = true ;
			}catch (e){
				alert('消息解析异常');
			}
		}else{
			this.isAppMsg = false ;
			this.text = tool.xssFilter(text);
		}
	};
	Msg.Elem.Text.prototype.getData = function() {
		return	this.data;
	};
	Msg.Elem.Text.prototype.getText = function() {
		return	this.text;
	};
	Msg.Elem.Text.prototype.toHtml = function() {
		return	this.text;
	};
        // class Msg.Elem.Face
	Msg.Elem.Face = function(index,data) {
		this.index = index;
		this.data = data;
	};
        Msg.Elem.Face.prototype.getIndex = function() {
                return this.index;
	};
        Msg.Elem.Face.prototype.getData = function() {
                return this.data;     
	};
        Msg.Elem.Face.prototype.toHtml = function() {
                var emotion=emotions[this.index];
		if(emotion && emotion[1]){
                    return	"<img src='" + emotion[1] + "'/>";
                }else{
                    return this.data;
                }
	};
        
        //图片消息
        // class Msg.Elem.Images
	Msg.Elem.Images = function(imageId) {
		this.UUID = imageId;
		this.ImageInfoArray=[];
	};
        Msg.Elem.Images.prototype.addImage = function(image) {
                this.ImageInfoArray.push(image);    
	};
        Msg.Elem.Images.prototype.toHtml = function() {
                var smallImage=this.getImage(IMAGE_TYPE.SMALL);
                var bigImage=this.getImage(IMAGE_TYPE.LARGE);
                var oriImage=this.getImage(IMAGE_TYPE.ORIGIN);
                if(!bigImage){
                    bigImage=smallImage;
                }
                if(!oriImage){
                    oriImage=smallImage;
                }
                return	"<img src='" + smallImage.getUrl() + "#"+bigImage.getUrl()+"#"+oriImage.getUrl()+"' style='CURSOR: hand' id='"+this.getImageId()+"' bigImgUrl='"+bigImage.getUrl()+"' onclick='imageClick(this)' />";
                
	}; 
        Msg.Elem.Images.prototype.getImageId = function() {
                return this.UUID;
	};
        Msg.Elem.Images.prototype.getImage = function(type) {
                for(var i in this.ImageInfoArray){
                    if(this.ImageInfoArray[i].getType()==type){
                        return this.ImageInfoArray[i];
                    }
                }
                return null;
	};
        // class Msg.Elem.Images.Image
	Msg.Elem.Images.Image = function(type,size,width,height,url) {
		this.type = type;
		this.size = size;
		this.width = width;
		this.height = height;
		this.url = url;
	};
        Msg.Elem.Images.Image.prototype.getType= function() {
                return this.type;  
	};
        Msg.Elem.Images.Image.prototype.getSize= function() {
                return this.size;  
	};
        Msg.Elem.Images.Image.prototype.getWidth= function() {
                return this.width;  
	};
        Msg.Elem.Images.Image.prototype.getHeight= function() {
                return this.height;  
	};
        Msg.Elem.Images.Image.prototype.getUrl= function() {
                return this.url;  
	};
        
        // class Msg.Elem.Sound
	Msg.Elem.Sound = function(uuid,second,size,senderId,downUrl) {
		this.uuid = uuid;//语音id
		this.second = second;//时长，单位：秒
		this.size = size;//大小，单位：字节
		this.senderId = senderId;//发送者id
		this.downUrl = downUrl;//下载url
	};
        Msg.Elem.Sound.prototype.getUUID = function() {
                return this.uuid;
	};
        Msg.Elem.Sound.prototype.getSecond = function() {
                return this.second;     
	};
        Msg.Elem.Sound.prototype.getSize = function() {
                return this.size;     
	};
        Msg.Elem.Sound.prototype.getSenderId = function() {
                return this.senderId;     
	};
        Msg.Elem.Sound.prototype.getDownUrl = function() {
                return this.downUrl;     
	};
        Msg.Elem.Sound.prototype.toHtml = function() {
                if(BROWSER_INFO.type=='ie' && parseInt(BROWSER_INFO.ver)<=8){
                    return '[这是一条语音消息]demo暂不支持ie8(含)以下浏览器播放语音,语音URL:'+this.downUrl;
                }
		return '<audio src="'+this.downUrl+'" controls="controls" onplay="onChangePlayAudio(this)" preload="none"></audio>';
	};
        
        // class Msg.Elem.File
	Msg.Elem.File = function(uuid,name,size,senderId,downUrl) {
		this.uuid = uuid;//文件id
		this.name = name;//文件名
		this.size = size;//大小，单位：字节
		this.senderId = senderId;//发送者
                this.downUrl = downUrl;//下载地址
	};
        Msg.Elem.File.prototype.getUUID = function() {
                return this.uuid;
	};
        Msg.Elem.File.prototype.getName = function() {
                return this.name;     
	};
        Msg.Elem.File.prototype.getSize = function() {
                return this.size;     
	};
        Msg.Elem.File.prototype.getSenderId = function() {
                return this.senderId;     
	};
        Msg.Elem.File.prototype.getDownUrl = function() {
                return this.downUrl;     
	};
        Msg.Elem.File.prototype.toHtml = function() {
                var fileSize=Math.round(this.size/1024);
		return '<a href="'+this.downUrl+'" title="点击下载文件" ><i class="glyphicon glyphicon-file">&nbsp;'+this.name+'('+fileSize+'KB)</i></a>';
	};
        
        // class Msg.Elem.GroupTip 群提示消息对象
	Msg.Elem.GroupTip = function(opType,opUserId,groupId,groupName,userIdList) {
		this.opType = opType;//操作类型
		this.opUserId = opUserId;//操作者id
		this.groupId = groupId;//群id
		this.groupName = groupName;//群名称
                this.userIdList = userIdList ? userIdList : [];//被操作的用户id列表
                this.groupInfoList = [];//新的群资料信息，群资料变更时才有值
                this.memberInfoList = [];//新的群成员资料信息，群成员资料变更时才有值
                this.groupMemberNum=null;//群成员数，操作类型为加群或者退群时才有值
	};
        Msg.Elem.GroupTip.prototype.addGroupInfo = function(groupInfo) {
                this.groupInfoList.push(groupInfo);   
	};
        Msg.Elem.GroupTip.prototype.addMemberInfo = function(memberInfo) {
                this.memberInfoList.push(memberInfo);    
	};
        Msg.Elem.GroupTip.prototype.getOpType = function() {
                return this.opType;
	};
        Msg.Elem.GroupTip.prototype.getOpUserId = function() {
                return this.opUserId;     
	};
        Msg.Elem.GroupTip.prototype.getGroupId = function() {
                return this.groupId;     
	};
        Msg.Elem.GroupTip.prototype.getGroupName = function() {
                return this.groupName;     
	};
        Msg.Elem.GroupTip.prototype.getUserIdList = function() {
                return this.userIdList;     
	};
        Msg.Elem.GroupTip.prototype.getGroupInfoList = function() {
                return this.groupInfoList;     
	};
        Msg.Elem.GroupTip.prototype.getMemberInfoList = function() {
                return this.memberInfoList;     
	};
        Msg.Elem.GroupTip.prototype.getGroupMemberNum = function() {
                return this.groupMemberNum;     
	};
        Msg.Elem.GroupTip.prototype.setGroupMemberNum = function(groupMemberNum) {
                return this.groupMemberNum=groupMemberNum;     
	};
        Msg.Elem.GroupTip.prototype.toHtml = function() {
                var text="[群提示消息]";
                var maxIndex=GROUP_TIP_MAX_USER_COUNT-1;
                switch (this.opType) {
                    case GROUP_TIP_TYPE.JOIN://加入群
                        text += this.opUserId + "邀请了";
                        for (var m in this.userIdList) {
                            text += this.userIdList[m] + ",";
                            if (this.userIdList.length > GROUP_TIP_MAX_USER_COUNT && m == maxIndex) {
                                text += "等" + this.userIdList.length + "人";
                                break;
                            }
                        }
                        text += "加入该群";
                        break;
                    case GROUP_TIP_TYPE.QUIT://退出群
                        text += this.opUserId + "主动退出该群";
                        break;
                    case GROUP_TIP_TYPE.KICK://踢出群
                        text += this.opUserId + "将";
                        for (var m in this.userIdList) {
                            text += this.userIdList[m] + ",";
                            if (this.userIdList.length > GROUP_TIP_MAX_USER_COUNT && m == maxIndex) {
                                text += "等" + this.userIdList.length + "人";
                                break;
                            }
                        }
                        text += "踢出该群";
                        break;
                    case GROUP_TIP_TYPE.SET_ADMIN://设置管理员
                        text += this.opUserId + "将";
                        for (var m in this.userIdList) {
                            text += this.userIdList[m] + ",";
                            if (this.userIdList.length > GROUP_TIP_MAX_USER_COUNT && m == maxIndex) {
                                text += "等" + this.userIdList.length + "人";
                                break;
                            }
                        }
                        text += "设为管理员";
                        break;
                    case GROUP_TIP_TYPE.CANCEL_ADMIN://取消管理员
                        text += this.opUserId + "取消";
                        for (var m in this.userIdList) {
                            text += this.userIdList[m] + ",";
                            if (this.userIdList.length > GROUP_TIP_MAX_USER_COUNT && m == maxIndex) {
                                text += "等" + this.userIdList.length + "人";
                                break;
                            }
                        }
                        text += "的管理员资格";
                        break;
        
                    case GROUP_TIP_TYPE.MODIFY_GROUP_INFO://群资料变更
                        text += this.opUserId + "修改了群资料：";
                        for (var m in this.groupInfoList) {
                            var type=this.groupInfoList[m].getType();
                            var value=this.groupInfoList[m].getValue();
                            switch(type){
                                case GROUP_TIP_MODIFY_GROUP_INFO_TYPE.FACE_URL:
                                    text += "群头像为" + value + "; ";
                                    break;
                                case GROUP_TIP_MODIFY_GROUP_INFO_TYPE.NAME:
                                    text += "群名称为" + value + "; ";
                                    break;
                                case GROUP_TIP_MODIFY_GROUP_INFO_TYPE.OWNER:
                                    text += "群主为" + value + "; ";
                                    break;
                                case GROUP_TIP_MODIFY_GROUP_INFO_TYPE.NOTIFICATION:
                                    text += "群公告为" + value + "; ";
                                    break;
                                case GROUP_TIP_MODIFY_GROUP_INFO_TYPE.INTRODUCTION:
                                    text += "群简介为" + value + "; ";
                                    break;
                                default:
                                    text += "未知信息为:type=" + type+",value="+value + "; ";
                                    break;
                            } 
                        }
                        break;
        
                    case GROUP_TIP_TYPE.MODIFY_MEMBER_INFO://群成员资料变更(禁言时间)
                        text += this.opUserId + "修改了群成员资料:";
                        for (var m in this.memberInfoList) {
                            var userId=this.memberInfoList[m].getUserId();
                            var shutupTime=this.memberInfoList[m].getShutupTime();
                            text += userId+": ";
                            if (shutupTime != null && shutupTime !== undefined) {
                                if (shutupTime == 0) {
                                    text += "取消禁言; ";
                                } else {
                                    text += "禁言" + shutupTime + "秒; ";
                                }
                            } else{
                                text += " shutupTime为空";
                            }
                            if (this.memberInfoList.length > GROUP_TIP_MAX_USER_COUNT && m == maxIndex) {
                                text += "等" + this.memberInfoList.length + "人";
                                break;
                            }
                        }
                        break;
                    default:
                        text += "未知群提示消息类型：type="+this.opType;
                        break;
                }
                return text;
	};
        
        // class Msg.Elem.GroupTip.GroupInfo，变更的群资料信息对象
	Msg.Elem.GroupTip.GroupInfo = function(type,value) {
		this.type = type;//群资料信息类型
		this.value = value;//对应的值
	};
        Msg.Elem.GroupTip.GroupInfo.prototype.getType = function() {
                return this.type;     
	};
        Msg.Elem.GroupTip.GroupInfo.prototype.getValue = function() {
                return this.value;     
	};
        
        // class Msg.Elem.GroupTip.MemberInfo，变更的群成员资料信息对象
	Msg.Elem.GroupTip.MemberInfo = function(userId,shutupTime) {
		this.userId = userId;//群成员id
		this.shutupTime = shutupTime;//群成员被禁言时间，0表示取消禁言，大于0表示被禁言时长，单位：秒
	};
        Msg.Elem.GroupTip.MemberInfo.prototype.getUserId = function() {
                return this.userId;     
	};
        Msg.Elem.GroupTip.MemberInfo.prototype.getShutupTime = function() {
                return this.shutupTime;     
	};
        
        // 自定义消息类型 class Msg.Elem.Custom
	Msg.Elem.Custom = function(data,desc,ext) {
		this.data =data;//数据
                this.desc =desc;//描述
                this.ext =ext;//扩展字段
	};
        Msg.Elem.Custom.prototype.getData = function() {
                return	this.data;
	};
        Msg.Elem.Custom.prototype.getDesc = function() {
                return	this.desc;
	};
        Msg.Elem.Custom.prototype.getExt = function() {
                return	this.ext;
	};
        Msg.Elem.Custom.prototype.toHtml = function() {
                return	this.data;
	};
        
	// singleton object MsgStore
	var MsgStore = new function() {
		var sessMap = {};//跟所有用户或群的聊天记录MAP
		var sessTimeline = [];//按时间降序排列的会话列表
		var msgCache = {};//消息缓存，用于判重
                //C2C
		this.cookie = "";//上一次拉取新c2c消息的cookie
		this.syncFlag = 0;//上一次拉取新c2c消息的是否继续拉取标记
                
		var visitSess = function(visitor) {
			for (var i in sessMap) {
				visitor(sessMap[i]);
			}
		};
                //消息查重
		var checkDupMsg = function(msg) {
			var dup = false;
			var first_key = msg.sess._impl.skey;
			var second_key = msg.isSend + msg.seq+msg.random;
			var tempMsg = msgCache[first_key] && msgCache[first_key][second_key];
			if (tempMsg && Math.abs(msg.time - tempMsg.time) < 1800)
				dup = true;
                        if(msgCache[first_key]){
                            msgCache[first_key][second_key] = {time: msg.time};
                        }else{
                            msgCache[first_key]={};
                            msgCache[first_key][second_key] = {time: msg.time};
                        }
			
			return dup;
		};
                
                this.sessMap=function(){
                    return sessMap;
                };
		this.sessCount = function() {
			return sessTimeline.length;
		};
		this.sessByTypeId = function(type, id) {
			var skey = Session.skey(type, id);
			if (skey === 'undefined' || skey == null) return null;
			return sessMap[skey];
		};
                this.delSessByTypeId = function(type, id) {
			var skey = Session.skey(type, id);
			if (skey === 'undefined' || skey == null) return false;
			if(sessMap[skey]){
                            delete sessMap[skey];
                            delete msgCache[skey];
                        }
                        return true;
		};
                this.resetCookieAndSyncFlag = function() {
			this.cookie = "";
                        this.syncFlag = 0;
		};
		
                //切换将当前会话的自动读取消息标志为isOn,重置其他会话的自动读取消息标志为false
		this.setAutoRead = function(selSess, isOn, isResetAll) {
			if (isResetAll)
				visitSess(function(s){s._impl.isAutoRead=false;});
			if (selSess) {
				selSess._impl.isAutoRead = isOn;//
				if (isOn) {//是否调用已读上报接口
                                    selSess._impl.unread = 0;
                                    
                                    if(selSess._impl.type==SESSION_TYPE.C2C){//私聊消息已读上报
                                        var tmpC2CMsgReadedItem=[];
                                        tmpC2CMsgReadedItem.push(new C2CMsgReadedItem(selSess._impl.id,selSess._impl.time));
                                        //调用C2C消息已读上报接口
                                        proto_c2CMsgReaded(MsgStore.cookie,
                                                      tmpC2CMsgReadedItem,
                                                      function(resp) { 
                                                          log.info("[setAutoRead]: c2CMsgReaded success");
                                                      },
                                                      function(err) {
                                                          log.error("[setAutoRead}: c2CMsgReaded failed:" + err.ErrorInfo);
                                                      });
                                    }else if(selSess._impl.type==SESSION_TYPE.GROUP){//群聊消息已读上报
                                        var tmpOpt={
                                            'GroupId':selSess._impl.id,
                                            'MsgReadedSeq':selSess._impl.curMaxMsgSeq
                                        };
                                        //调用group消息已读上报接口
                                        proto_groupMsgReaded(tmpOpt,
                                                      function(resp) {
                                                          log.info("groupMsgReaded success");
                                                                         
                                                      },
                                                      function(err) {
                                                          log.error("groupMsgReaded failed:" + err.ErrorInfo);
                                                        
                                                      });
                                    }  
                                }
			}
		};
                
                this.c2CMsgReaded=function(opts,cbOk,cbErr){
                    var tmpC2CMsgReadedItem=[];
                    tmpC2CMsgReadedItem.push(new C2CMsgReadedItem(opts.To_Account,opts.LastedMsgTime));
                    //调用C2C消息已读上报接口
                    proto_c2CMsgReaded(MsgStore.cookie,
                        tmpC2CMsgReadedItem,
                            function(resp) {  
                                if(cbOk){
                                    log.info("c2CMsgReaded success");
                                    cbOk(resp);
                                } 
                            },
                            function(err) {
                                if(cbErr){
                                    log.error("c2CMsgReaded failed:" + err.ErrorInfo);
                                    cbErr(err);
                                }
                            });
                };
                
		this.addSession = function(sess) {
			sessMap[sess._impl.skey] = sess;
		};
		this.delSession = function(sess) {
			delete sessMap[sess._impl.skey];
		};
		this.addMsg = function(msg) {
			if (checkDupMsg(msg)) return false;
			var sess = msg.sess;
			if (!sessMap[sess._impl.skey]) this.addSession(sess);
			sess._impl_addMsg(msg);
			return true;
		};
		this.updateTimeline = function() {
			var arr = new Array;
			visitSess(function(sess){arr.push(sess);});
			arr.sort(function(a,b){return b.time-a.time;});
			sessTimeline = arr;
		};
	};
	// singleton object MsgManager
	var MsgManager = new function() {
            
                var onMsgCallback = null;//新消息(c2c和group)回调
            
		var onGroupInfoChangeCallback = null;//群资料变化回调
                //收到新群系统消息回调列表
                var onGroupSystemNotifyCallbacks={
                    "1":null,
                    "2":null,
                    "3":null,
                    "4":null,
                    "5":null,
                    "6":null,
                    "7":null,
                    "8":null,
                    "9":null,
                    "10":null,
                    "11":null,
                    "255":null
                };
                //监听好友系统通知函数
                var onGroupFriendNotifyCallbacks={
                    "1":null,
                    "2":null,
                    "3":null,
                    "4":null,
                    "5":null,
                    "6":null,
                    "7":null,
                    "8":null
                };
                
                //普通长轮询
                var longPollingOn=false;//是否开启普通长轮询
                var isLongPollingRequesting=false;//是否在长轮询ing
                var notifySeq=0;//c2c通知seq
                var noticeSeq=0;//群消息seq
                
                //大群长轮询
                var onBigGroupMsgCallback=null;//大群消息回调
                var bigGroupLongPollingOn=false;//是否开启长轮询
                var bigGroupLongPollingStartSeq=0;//请求拉消息的起始seq(大群长轮询)
                var bigGroupLongPollingHoldTime=90;//客户端长轮询的超时时间，单位是秒(大群长轮询)
                var bigGroupLongPollingKey=null;//客户端加入群组后收到的的Key(大群长轮询)
                var bigGroupLongPollingMsgMap={};//记录收到的群消息数
                
                
                var ipList=[];//文件下载地址
                var authkey=null;//文件下载票据
                var expireTime=null;//票据超时时间
                
                var getLostGroupMsgCount=0;//补拉丢失的群消息次数
                //我的群当前最大的seq
                var myGroupMaxSeqs={};//用于补拉丢失的群消息
                
                var groupSystemMsgsCache={};//群组系统消息缓存,用于判重  
                
                //设置长轮询开关
                //isOn=true 开启
                //isOn=false 停止
                this.setLongPollingOn=function(isOn){
                    longPollingOn=isOn;
                };
                this.getLongPollingOn=function(){
                    return longPollingOn;
                };
                
                //重置长轮询变量
                this.resetLongPollingInfo=function(){
                    longPollingOn=false;
                    notifySeq=0;
                    noticeSeq=0;
                };
                
                //设置大群长轮询开关
                //isOn=true 开启
                //isOn=false 停止
                this.setBigGroupLongPollingOn=function(isOn){
                    bigGroupLongPollingOn=isOn;
                };
                //设置大群长轮询key
                this.setBigGroupLongPollingKey=function(key){
                    bigGroupLongPollingKey=key;
                };
                //重置大群长轮询变量
                this.resetBigGroupLongPollingInfo=function(){
                    bigGroupLongPollingOn=false;
                    bigGroupLongPollingStartSeq=0;
                    bigGroupLongPollingKey=null;
                    bigGroupLongPollingMsgMap={};
                };
                
                //设置群消息数据条数
                this.setBigGroupLongPollingMsgMap=function(groupId,count){
                    var bigGroupLongPollingMsgCount=bigGroupLongPollingMsgMap[groupId];
                    if(bigGroupLongPollingMsgCount){
                        bigGroupLongPollingMsgCount=parseInt(bigGroupLongPollingMsgCount)+count;
                        bigGroupLongPollingMsgMap[groupId]=bigGroupLongPollingMsgCount;
                    }else{
                        bigGroupLongPollingMsgMap[groupId]=count;
                    }
                };
                
                //重置
                this.clear=function(){
                    
                    onGroupInfoChangeCallback=null;
                    onGroupSystemNotifyCallbacks={
                        "1":null,//申请加群请求（只有管理员会收到）
                        "2":null,//申请加群被同意（只有申请人能够收到）
                        "3":null,//申请加群被拒绝（只有申请人能够收到）
                        "4":null,//被管理员踢出群(只有被踢者接收到)
                        "5":null,//群被解散(全员接收)
                        "6":null,//创建群(创建者接收)
                        "7":null,//邀请加群(被邀请者接收)
                        "8":null,//主动退群(主动退出者接收)
                        "9":null,//设置管理员(被设置者接收)
                        "10":null,//取消管理员(被取消者接收)
                        "11":null,//群已被回收(全员接收)
                        "255":null//用户自定义通知(默认全员接收)
                    };
                    onFriendSystemNotifyCallbacks={
                        "1":null,//好友表增加
                        "2":null,//好友表删除
                        "3":null,//未决增加
                        "4":null,//未决删除
                        "5":null,//黑名单增加
                        "6":null,//黑名单删除
                        "7":null,//未决已读上报
                        "8":null//好友信息(备注，分组)变更
                    };
                    onProfileSystemNotifyCallbacks={
                        "1":null//资料修改
                    };
                    //重置普通长轮询参数
                    onMsgCallback=null;
                    longPollingOn=false;
                    notifySeq=0;//c2c新消息通知seq
                    noticeSeq=0;//group新消息seq
                    
                    //重置大群长轮询参数
                    onBigGroupMsgCallback=null;
                    bigGroupLongPollingOn=false;
                    bigGroupLongPollingStartSeq=0;
                    bigGroupLongPollingKey=null;
                    bigGroupLongPollingMsgMap={};
                    
                    groupSystemMsgsCache={};
                    
                    ipList=[];//文件下载地址
                    authkey=null;//文件下载票据
                    expireTime=null;//票据超时时间
                };
                
                //初始化文件下载ip和票据
                var initIpAndAuthkey=function(cbOk,cbErr){
                    proto_getIpAndAuthkey(function(resp){
                            ipList=resp.IpList;
                            authkey=resp.AuthKey;
                            expireTime=resp.ExpireTime;
                            if(cbOk) cbOk(resp);
                        },
                        function(err) {
				log.error("initIpAndAuthkey failed:" + err.ErrorInfo);
				if (cbErr) cbErr(err);
			}
                    );
                };
                
                //初始化我的群当前最大的seq，用于补拉丢失的群消息
                var initMyGroupMaxSeqs=function(cbOk,cbErr){
                    var opts={
                        'Member_Account': ctx.identifier,
                        'Limit': 1000,
                        'Offset': 0,
                        'GroupBaseInfoFilter': [
                            'NextMsgSeq'
                        ]
                    };
                    proto_getJoinedGroupListHigh(opts,function(resp){
                            if (!resp.GroupIdList || resp.GroupIdList.length == 0) {
                                log.info("initMyGroupMaxSeqs: 目前还没有加入任何群组");
                                if(cbOk) cbOk(resp);
                                return;
                            }
                            for (var i = 0; i < resp.GroupIdList.length; i++) {
                                var group_id = resp.GroupIdList[i].GroupId;
                                var curMaxSeq = resp.GroupIdList[i].NextMsgSeq-1;
                                myGroupMaxSeqs[group_id]=curMaxSeq;
                            }
                            
                            if(cbOk) cbOk(resp);
                            
                        },
                        function(err) {
				log.error("initMyGroupMaxSeqs failed:" + err.ErrorInfo);
				if (cbErr) cbErr(err);
			}
                    );
                };
                
                //补拉群消息
                var getLostGroupMsgs=function(groupId,reqMsgSeq,reqMsgNumber){
                    getLostGroupMsgCount++;
                    //发起一个拉群群消息请求
                    var tempOpts={
                        'GroupId':  groupId,
                        'ReqMsgSeq':  reqMsgSeq,
                        'ReqMsgNumber':  reqMsgNumber
                    };
                    //发起一个拉群群消息请求
                    log.warn("第"+getLostGroupMsgCount+"次补齐群消息,参数="+JSON.stringify(tempOpts));
                    MsgManager.syncGroupMsgs(tempOpts);
                };
                
                //添加群消息列表
                var addGroupMsgList=function(msgs,new_group_msgs){
                    for(var p in msgs){
                            var newGroupMsg=msgs[p];                  
                            //发群消息时，长轮询接口会返回用户自己发的群消息，如果收到自己发的群消息，则不要处理
                            //if(newGroupMsg.From_Account && newGroupMsg.From_Account!=ctx.identifier ){
                            if(newGroupMsg.From_Account){
                                var msg=handlerGroupMsg(newGroupMsg,false,true);
                                    if(msg){
                                        new_group_msgs.push(msg);
                                    } 
                            }
                    }
                    return new_group_msgs;
                };
                
                //处理收到的群普通和提示消息
                var handlerOrdinaryAndTipGroupMsgs=function(eventType,groupMsgArray){
                                    var groupMsgMap = {};//
                                    var new_group_msgs=[];
                                    var minGroupMsgSeq=99999999;
                                    var maxGroupMsgSeq=-1;
                                    for(var j in groupMsgArray){
                                        
                                        var groupMsgs=groupMsgMap[groupMsgArray[j].ToGroupId];
                                        if(!groupMsgs){
                                            groupMsgs=groupMsgMap[groupMsgArray[j].ToGroupId]={
                                                "min":minGroupMsgSeq,//收到新消息最小seq
                                                "max":maxGroupMsgSeq,//收到新消息最大seq
                                                "msgs":[]//收到的新消息
                                            };
                                        }
                                        //更新noticeseq
                                        if(groupMsgArray[j].NoticeSeq>noticeSeq){
                                            log.warn("noticeSeq="+noticeSeq+",msgNoticeSeq="+groupMsgArray[j].NoticeSeq);
                                            noticeSeq=groupMsgArray[j].NoticeSeq;
                                        }
                                        groupMsgArray[j].Event=eventType;
                                        groupMsgMap[groupMsgArray[j].ToGroupId].msgs.push(groupMsgArray[j]);
                                        if(groupMsgArray[j].MsgSeq<groupMsgs.min){
                                            groupMsgMap[groupMsgArray[j].ToGroupId].min=groupMsgArray[j].MsgSeq;
                                        }
                                        if(groupMsgArray[j].MsgSeq>groupMsgs.max){
                                            groupMsgMap[groupMsgArray[j].ToGroupId].max=groupMsgArray[j].MsgSeq;
                                        }
                                    }
                                    
                                    for(var groupId in groupMsgMap){
                                        var tempCount=groupMsgMap[groupId].max-groupMsgMap[groupId].min+1;
                                        var curMaxMsgSeq=myGroupMaxSeqs[groupId];
                                        if(curMaxMsgSeq){//存在这个群的最大消息seq
                                            //高并发情况下，长轮询可能存在丢消息，这时需要客户端通过拉取群消息接口补齐下
                                            //1、如果收到的新消息最小seq比当前最大群消息seq大于1，则表示收到的群消息发生跳跃，需要补齐
                                            //2、收到的新群消息seq存在不连续情况，也需要补齐
                                            if(groupMsgMap[groupId].min-curMaxMsgSeq>1 || groupMsgMap[groupId].msgs.length<tempCount){
                                                //发起一个拉群群消息请求
                                                log.warn("发起一次补齐群消息请求,curMaxMsgSeq="+curMaxMsgSeq+", minMsgSeq="+groupMsgMap[groupId].min+", maxMsgSeq="+groupMsgMap[groupId].max+", msgs.length="+groupMsgMap[groupId].msgs.length+", tempCount="+tempCount);
                                                getLostGroupMsgs(groupId,groupMsgMap[groupId].max,groupMsgMap[groupId].max-curMaxMsgSeq);
                                            }else{
                                                new_group_msgs=addGroupMsgList(groupMsgMap[groupId].msgs,new_group_msgs);
                                            }
                                        }else{//不存在改群的最大消息seq
                                            log.warn("不存在该群的最大消息seq，群id="+groupId);
                                            //高并发情况下，长轮询可能存在丢消息，这时需要客户端通过拉取群消息接口补齐下
                                            //1、收到的新群消息seq存在不连续情况，也需要补齐
                                            if(groupMsgMap[groupId].msgs.length<tempCount){
                                                //发起一个拉群群消息请求
                                                log.warn("发起一次补齐群消息请求,minMsgSeq="+groupMsgMap[groupId].min+", maxMsgSeq="+groupMsgMap[groupId].max+", msgs.length="+groupMsgMap[groupId].msgs.length+", tempCount="+tempCount);
                                                getLostGroupMsgs(groupId,groupMsgMap[groupId].max,tempCount);
                                                
                                            }else{
                                                new_group_msgs=addGroupMsgList(groupMsgMap[groupId].msgs,new_group_msgs); 
                                            }
                                        }
                                    }
                                    if(new_group_msgs.length ){
                                        MsgStore.updateTimeline();
                                    }
                                    if(onMsgCallback && new_group_msgs.length) onMsgCallback(new_group_msgs);
                                
                };
                
                //处理新的群提示消息
                var handlerGroupTips=function(groupTips){
                                    var new_group_msgs=[];
                                    for(var o in groupTips){
                                        var groupTip=groupTips[o];
                                        //添加event字段
                                        groupTip.Event=LONG_POLLINNG_EVENT_TYPE.GROUP_TIP;
                                        //更新群消息通知seq
                                        if(groupTip.NoticeSeq>noticeSeq){
                                            noticeSeq=groupTip.NoticeSeq;
                                        }
                                        var msg=handlerGroupMsg(groupTip,false,true);
                                        if(msg){
                                            new_group_msgs.push(msg);
                                        }
                                    }
                                    if(new_group_msgs.length ){
                                        MsgStore.updateTimeline();
                                    }
                                    if(onMsgCallback && new_group_msgs.length) onMsgCallback(new_group_msgs);
                };
                
                //处理新的群系统消息
                //isNeedValidRepeatMsg 是否需要判重
                var handlerGroupSystemMsgs=function(groupSystemMsgs,isNeedValidRepeatMsg){
                                    for(var k in groupSystemMsgs){
                                        var groupTip=groupSystemMsgs[k];
                                        var groupReportTypeMsg=groupTip.MsgBody;
                                        var reportType=groupReportTypeMsg.ReportType;
                                        //当长轮询返回的群系统消息，才需要更新群消息通知seq
                                        if(isNeedValidRepeatMsg==false && groupTip.NoticeSeq && groupTip.NoticeSeq>noticeSeq){
                                            noticeSeq=groupTip.NoticeSeq;
                                        }
                                        var toAccount=groupTip.GroupInfo.To_Account;
                                        //过滤本不应该给自己的系统消息
                                        if(!toAccount || toAccount!=ctx.identifier){
                                            log.error("收到本不应该给自己的系统消息: To_Account="+toAccount);
                                            continue;
                                        }
                                        if(isNeedValidRepeatMsg){
                                            //var key=groupTip.ToGroupId+"_"+reportType+"_"+groupTip.MsgTimeStamp+"_"+groupReportTypeMsg.Operator_Account;
                                            var key=groupTip.ToGroupId+"_"+reportType+"_"+groupReportTypeMsg.Operator_Account;
                                            var isExist=groupSystemMsgsCache[key];
                                            if(isExist){
                                                log.warn("收到重复的群系统消息：key="+key);
                                                continue;
                                            }
                                            groupSystemMsgsCache[key]=true;
                                        }
                                        
                                        var notify={
                                                    "SrcFlag":0,
                                                    "ReportType":reportType,
                                                    "GroupId":groupTip.ToGroupId,
                                                    "GroupName":groupTip.GroupInfo.GroupName,
                                                    "Operator_Account":groupReportTypeMsg.Operator_Account,
                                                    "MsgTime":groupTip.MsgTimeStamp
                                        };
                                        switch(reportType){
                                            case GROUP_SYSTEM_TYPE.JOIN_GROUP_REQUEST://申请加群(只有管理员会接收到)
                                                notify["RemarkInfo"]=groupReportTypeMsg.RemarkInfo;
                                                notify["MsgKey"]=groupReportTypeMsg.MsgKey;
                                                notify["Authentication"]=groupReportTypeMsg.Authentication;
                                                notify["UserDefinedField"]=groupTip.UserDefinedField;
                                                notify["From_Account"]=groupTip.From_Account;
                                                notify["MsgSeq"]=groupTip.ClientSeq;
                                                notify["MsgRandom"]=groupTip.MsgRandom;
                                                break;
                                            case GROUP_SYSTEM_TYPE.JOIN_GROUP_ACCEPT://申请加群被同意(只有申请人自己接收到)
                                            case GROUP_SYSTEM_TYPE.JOIN_GROUP_REFUSE://申请加群被拒绝(只有申请人自己接收到)
                                                notify["RemarkInfo"]=groupReportTypeMsg.RemarkInfo;
                                                break;
                                            case GROUP_SYSTEM_TYPE.KICK://被管理员踢出群(只有被踢者接收到)
                                            case GROUP_SYSTEM_TYPE.DESTORY://群被解散(全员接收)
                                            case GROUP_SYSTEM_TYPE.CREATE://创建群(创建者接收, 不展示)
                                            case GROUP_SYSTEM_TYPE.INVITED_JOIN_GROUP_REQUEST://邀请加群(被邀请者接收)
                                            case GROUP_SYSTEM_TYPE.QUIT://主动退群(主动退出者接收, 不展示)
                                            case GROUP_SYSTEM_TYPE.SET_ADMIN://群设置管理员(被设置者接收)
                                            case GROUP_SYSTEM_TYPE.CANCEL_ADMIN://取消管理员(被取消者接收)
                                            case GROUP_SYSTEM_TYPE.REVOKE://群已被回收(全员接收, 不展示)
                                                break;
                                            case GROUP_SYSTEM_TYPE.CUSTOM://用户自定义通知(默认全员接收)
                                                notify["MsgSeq"]=groupTip.MsgSeq;
                                                notify["UserDefinedField"]=groupReportTypeMsg.UserDefinedField;
                                                break;
                                            default:
                                                log.error("未知群系统消息类型：reportType="+reportType);
                                                break;
                                        }
                                        
                                        if(isNeedValidRepeatMsg){
                                            if(reportType==GROUP_SYSTEM_TYPE.JOIN_GROUP_REQUEST){
                                                //回调
                                                if(onGroupSystemNotifyCallbacks[reportType]) onGroupSystemNotifyCallbacks[reportType](notify);
                                            }
                                        }else{
                                            //回调
                                            if(onGroupSystemNotifyCallbacks[reportType]) onGroupSystemNotifyCallbacks[reportType](notify);
                                        }
                                    }//loop 
                };
                
                
                //处理新的好友系统通知
                //isNeedValidRepeatMsg 是否需要判重
                var handlerFriendSystemNotices=function(friendSystemNotices,isNeedValidRepeatMsg){
                                    var friendNotice,type,notify;
                                    for(var k in friendSystemNotices){
                                        friendNotice=friendSystemNotices[k];
                                        type=friendNotice.PushType;
                                        //当长轮询返回的群系统消息，才需要更新通知seq
                                        if(isNeedValidRepeatMsg==false && friendNotice.NoticeSeq && friendNotice.NoticeSeq>noticeSeq){
                                            noticeSeq=friendNotice.NoticeSeq;
                                        }
                                        notify={'Type':type};
                                        switch(type){
                                            case FRIEND_NOTICE_TYPE.FRIEND_ADD://好友表增加
                                                notify["Accounts"]=friendNotice.FriendAdd_Account;
                                                break;
                                            case FRIEND_NOTICE_TYPE.FRIEND_DELETE://好友表删除
                                                notify["Accounts"]=friendNotice.FriendDel_Account;
                                                break;
                                            case FRIEND_NOTICE_TYPE.PENDENCY_ADD://未决增加
                                                notify["PendencyList"]=friendNotice.PendencyAdd;
                                                break;
                                            case FRIEND_NOTICE_TYPE.PENDENCY_DELETE://未决删除
                                                notify["Accounts"]=friendNotice.FrienPencydDel_Account;
                                                break;
                                            case FRIEND_NOTICE_TYPE.BLACK_LIST_ADD://黑名单增加
                                                notify["Accounts"]=friendNotice.BlackListAdd_Account;
                                                break;
                                            case FRIEND_NOTICE_TYPE.BLACK_LIST_DELETE://黑名单删除
                                                notify["Accounts"]=friendNotice.BlackListDel_Account;
                                                break;
                                            /*case FRIEND_NOTICE_TYPE.PENDENCY_REPORT://未决已读上报
                                                
                                                break;
                                            case FRIEND_NOTICE_TYPE.FRIEND_UPDATE://好友数据更新
                                                
                                                break;
                                            */
                                            default:
                                                log.error("未知好友系统通知类型：friendNotice="+JSON.stringify(friendNotice));
                                                break;
                                        }
                                        
                                        if(isNeedValidRepeatMsg){
                                            if(type==FRIEND_NOTICE_TYPE.PENDENCY_ADD){
                                                //回调
                                                if(onFriendSystemNotifyCallbacks[type]) onFriendSystemNotifyCallbacks[type](notify);
                                            }
                                        }else{
                                            //回调
                                            if(onFriendSystemNotifyCallbacks[type]) onFriendSystemNotifyCallbacks[type](notify);
                                        }
                                    }//loop 
                };
                
                //处理新的资料系统通知
                //isNeedValidRepeatMsg 是否需要判重
                var handlerProfileSystemNotices=function(profileSystemNotices,isNeedValidRepeatMsg){
                                    var profileNotice,type,notify;
                                    for(var k in profileSystemNotices){
                                        profileNotice=profileSystemNotices[k];
                                        type=profileNotice.PushType;
                                        //当长轮询返回的群系统消息，才需要更新通知seq
                                        if(isNeedValidRepeatMsg==false && profileNotice.NoticeSeq && profileNotice.NoticeSeq>noticeSeq){
                                            noticeSeq=profileNotice.NoticeSeq;
                                        }
                                        notify={'Type':type};
                                        switch(type){
                                            case PROFILE_NOTICE_TYPE.PROFILE_MODIFY://资料修改
                                                notify["Profile_Account"]=profileNotice.Profile_Account;
                                                notify["ProfileList"]=profileNotice.ProfileList;
                                                break;
                                            default:
                                                log.error("未知资料系统通知类型：profileNotice="+JSON.stringify(profileNotice));
                                                break;
                                        }
                                        
                                        if(isNeedValidRepeatMsg){
                                            if(type==PROFILE_NOTICE_TYPE.PROFILE_MODIFY){
                                                //回调
                                                if(onProfileSystemNotifyCallbacks[type]) onProfileSystemNotifyCallbacks[type](notify);
                                            }
                                        }else{
                                            //回调
                                            if(onProfileSystemNotifyCallbacks[type]) onProfileSystemNotifyCallbacks[type](notify);
                                        }
                                    }//loop 
                };
                
                //处理新的群系统消息(用于直播大群长轮询)
                var handlerGroupSystemMsg=function(groupTip){
                                        var groupReportTypeMsg=groupTip.MsgBody;
                                        var reportType=groupReportTypeMsg.ReportType;
                                        var toAccount=groupTip.GroupInfo.To_Account;
                                        //过滤本不应该给自己的系统消息
                                        //if(!toAccount || toAccount!=ctx.identifier){
                                        //    log.error("收到本不应该给自己的系统消息: To_Account="+toAccount);
                                        //    continue;
                                        //}
                                        var notify={
                                                    "SrcFlag":1,
                                                    "ReportType":reportType,
                                                    "GroupId":groupTip.ToGroupId,
                                                    "GroupName":groupTip.GroupInfo.GroupName,
                                                    "Operator_Account":groupReportTypeMsg.Operator_Account,
                                                    "MsgTime":groupTip.MsgTimeStamp
                                        };
                                        switch(reportType){
                                            case GROUP_SYSTEM_TYPE.JOIN_GROUP_REQUEST://申请加群(只有管理员会接收到)
                                                notify["RemarkInfo"]=groupReportTypeMsg.RemarkInfo;
                                                notify["MsgKey"]=groupReportTypeMsg.MsgKey;
                                                notify["Authentication"]=groupReportTypeMsg.Authentication;
                                                notify["UserDefinedField"]=groupTip.UserDefinedField;
                                                notify["From_Account"]=groupTip.From_Account;
                                                notify["MsgSeq"]=groupTip.ClientSeq;
                                                notify["MsgRandom"]=groupTip.MsgRandom;
                                                break;
                                            case GROUP_SYSTEM_TYPE.JOIN_GROUP_ACCEPT://申请加群被同意(只有申请人自己接收到)
                                            case GROUP_SYSTEM_TYPE.JOIN_GROUP_REFUSE://申请加群被拒绝(只有申请人自己接收到)
                                                notify["RemarkInfo"]=groupReportTypeMsg.RemarkInfo;
                                                break;
                                            case GROUP_SYSTEM_TYPE.KICK://被管理员踢出群(只有被踢者接收到)
                                            case GROUP_SYSTEM_TYPE.DESTORY://群被解散(全员接收)
                                            case GROUP_SYSTEM_TYPE.CREATE://创建群(创建者接收, 不展示)
                                            case GROUP_SYSTEM_TYPE.INVITED_JOIN_GROUP_REQUEST://邀请加群(被邀请者接收)
                                            case GROUP_SYSTEM_TYPE.QUIT://主动退群(主动退出者接收, 不展示)
                                            case GROUP_SYSTEM_TYPE.SET_ADMIN://群设置管理员(被设置者接收)
                                            case GROUP_SYSTEM_TYPE.CANCEL_ADMIN://取消管理员(被取消者接收)
                                            case GROUP_SYSTEM_TYPE.REVOKE://群已被回收(全员接收, 不展示)
                                                break;
                                            case GROUP_SYSTEM_TYPE.CUSTOM://用户自定义通知(默认全员接收)
                                                notify["MsgSeq"]=groupTip.MsgSeq;
                                                notify["UserDefinedField"]=groupReportTypeMsg.UserDefinedField;
                                                break;
                                            default:
                                                log.error("未知群系统消息类型：reportType="+reportType);
                                                break;
                                        }
                                        //回调
                                        if(onGroupSystemNotifyCallbacks[reportType]) onGroupSystemNotifyCallbacks[reportType](notify);
                                    
                };
                
                //长轮询
                this.longPolling=function(cbOk,cbErr){
                    var opts={
                        'Timeout':90,
                        'Cookie':{
                            'NotifySeq':notifySeq,
                            'NoticeSeq':noticeSeq
                        }
                    };
                    proto_longPolling(opts,function(resp) {
                        for(var i in resp.EventArray){
                            var e=resp.EventArray[i];
                            switch(e.Event){
                                case LONG_POLLINNG_EVENT_TYPE.C2C://c2c消息通知
                                    //更新C2C消息通知seq
                                    notifySeq=e.NotifySeq;
                                    log.warn("longpolling: received new c2c msg");
                                     //获取新消息
                                     MsgManager.syncMsgs();
                                    break;
                                case LONG_POLLINNG_EVENT_TYPE.GROUP_COMMON://普通群消息通知
                                    log.warn("longpolling: received new group msgs");
                                    handlerOrdinaryAndTipGroupMsgs(e.Event,e.GroupMsgArray);
                                    break;
                                case LONG_POLLINNG_EVENT_TYPE.GROUP_TIP://（全员广播）群提示消息
                                    log.warn("longpolling: received new group tips");
                                    handlerOrdinaryAndTipGroupMsgs(e.Event,e.GroupTips);
                                    break;
                                case LONG_POLLINNG_EVENT_TYPE.GROUP_SYSTEM://（多终端同步）群系统消息
                                    log.warn("longpolling: received new group system msgs");
                                    //false 表示 通过长轮询收到的群系统消息，可以不判重
                                    handlerGroupSystemMsgs(e.GroupTips,false);
                                    break;
                                case LONG_POLLINNG_EVENT_TYPE.FRIEND_NOTICE://好友系统通知
                                    log.warn("longpolling: received new friend system notice");
                                    //false 表示 通过长轮询收到的好友系统通知，可以不判重
                                    handlerFriendSystemNotices(e.FriendListMod,false);
                                    break;
                                case LONG_POLLINNG_EVENT_TYPE.PROFILE_NOTICE://资料系统通知
                                    log.warn("longpolling: received new profile system notice");
                                    //false 表示 通过长轮询收到的资料系统通知，可以不判重
                                    handlerProfileSystemNotices(e.ProfileDataMod,false);
                                    break;
                                default:
                                    log.error("longpolling收到未知新消息类型: Event="+e.Event);
                                    break;
                            }
                        }
                        var successInfo={
                            'ActionStatus':ACTION_STATUS.OK,
                            'ErrorCode':0
                        };
                        updatecLongPollingStatus(successInfo);
                    }, function(err) {
                                //log.error(err);
                                updatecLongPollingStatus(err);
				if (cbErr) cbErr(err); 
			});
                };
                
                
                //大群 长轮询
                this.bigGroupLongPolling=function(cbOk,cbErr){
                    
                    var opts={
                        'StartSeq':bigGroupLongPollingStartSeq,//请求拉消息的起始seq
                        'HoldTime':bigGroupLongPollingHoldTime,//客户端长轮询的超时时间，单位是秒
                        'Key':bigGroupLongPollingKey//客户端加入群组后收到的的Key
                    };
                    
                    proto_bigGroupLongPolling(opts,function(resp) {
                        
                        var msgObjList = [];
                        bigGroupLongPollingStartSeq=resp.NextSeq;
                        bigGroupLongPollingHoldTime=resp.HoldTime;
                        bigGroupLongPollingKey=resp.Key;
                        
                        if(resp.RspMsgList && resp.RspMsgList.length>0){
                            var msgCount=0,msgInfo,event,msg;
                            for (var i=resp.RspMsgList.length-1;i>=0;i--) {
                                    msgInfo = resp.RspMsgList[i];
                                    //如果是已经删除的消息或者发送者帐号为空或者消息内容为空
                                    //IsPlaceMsg=1
                                    if(msgInfo.IsPlaceMsg || !msgInfo.From_Account || !msgInfo.MsgBody || msgInfo.MsgBody.length==0){
                                        continue;
                                    }
                                    
                                    event=msgInfo.Event;//群消息类型
                                    switch(event){
                                        case LONG_POLLINNG_EVENT_TYPE.GROUP_COMMON://群普通消息
                                            log.info("bigGroupLongPolling: return new group msg");
                                            msg=handlerGroupMsg(msgInfo,false,false);
                                            msg && msgObjList.push(msg);
                                            msgCount=msgCount+1;
                                            break;
                                        case LONG_POLLINNG_EVENT_TYPE.GROUP_TIP://群提示消息
                                        case LONG_POLLINNG_EVENT_TYPE.GROUP_TIP2://群提示消息
                                            log.info("bigGroupLongPolling: return new group tip");
                                            msg=handlerGroupMsg(msgInfo,false,false);
                                            msg && msgObjList.push(msg);
                                            //msgCount=msgCount+1;
                                            break;
                                        case LONG_POLLINNG_EVENT_TYPE.GROUP_SYSTEM://群系统消息
                                            log.info("bigGroupLongPolling: new group system msg");
                                            handlerGroupSystemMsg(msgInfo);
                                            break;
                                        default:
                                            log.error("bigGroupLongPolling收到未知新消息类型: Event="+event);
                                            break;
                                    }   
                            } // for loop
                            if (msgCount>0){
                                MsgManager.setBigGroupLongPollingMsgMap(msgInfo.ToGroupId,msgCount);//
                                log.warn("current bigGroupLongPollingMsgMap: "+JSON.stringify(bigGroupLongPollingMsgMap));
                            }
                        }
                        curBigGroupLongPollingRetErrorCount=0;
                        //返回连接状态
                        var successInfo={
                            'ActionStatus':ACTION_STATUS.OK,
                            'ErrorCode':CONNECTION_STATUS.ON,
                            'ErrorInfo':'connection is ok...'
                        };
                        ConnManager.callBack(successInfo);
                        
                        if (cbOk) cbOk(msgObjList);
                        else if(onBigGroupMsgCallback) onBigGroupMsgCallback(msgObjList);//返回新消息
                        
                        //重新启动长轮询
                        bigGroupLongPollingOn && MsgManager.bigGroupLongPolling();
                        
                    }, function(err) {
                                //
                                if(err.ErrorCode!=longPollingTimeOutErrorCode){
                                    log.error(err.ErrorInfo);
                                    //记录长轮询返回错误次数
                                    curBigGroupLongPollingRetErrorCount++;
                                }
                                //累计超过一定次数，不再发起长轮询请求
                                if(curBigGroupLongPollingRetErrorCount<LONG_POLLING_MAX_RET_ERROR_COUNT){
                                    bigGroupLongPollingOn && MsgManager.bigGroupLongPolling();
                                }else{
                                    var errInfo={
                                        'ActionStatus':ACTION_STATUS.FAIL,
                                        'ErrorCode':CONNECTION_STATUS.OFF,
                                        'ErrorInfo':'connection is off'
                                    };
                                    ConnManager.callBack(errInfo);
                                }
				if (cbErr) cbErr(err);
                                
			},bigGroupLongPollingHoldTime*1000);
                };
                
                //更新连接状态
                var updatecLongPollingStatus=function(errObj){
                    if(errObj.ErrorCode==0 || errObj.ErrorCode==longPollingTimeOutErrorCode){
                        curLongPollingRetErrorCount=0;
                        longPollingOffCallbackFlag=false;
                        var errorInfo;
                        var isNeedCallback=false;
                        switch(curLongPollingStatus){
                            case CONNECTION_STATUS.INIT:
                                isNeedCallback=true;
                                curLongPollingStatus=CONNECTION_STATUS.ON;
                                errorInfo="create connection successfully(INIT->ON)";
                                break;
                            case CONNECTION_STATUS.ON:
                                errorInfo="connection is on...(ON->ON)";
                                break;
                            case CONNECTION_STATUS.RECONNECT:
                                curLongPollingStatus=CONNECTION_STATUS.ON;
                                errorInfo="connection is on...(RECONNECT->ON)";
                                break;
                            case CONNECTION_STATUS.OFF:
                                isNeedCallback=true;
                                curLongPollingStatus=CONNECTION_STATUS.RECONNECT;
                                errorInfo="reconnect successfully(OFF->RECONNECT)";
                                break;
                        }
                        var successInfo={
                            'ActionStatus':ACTION_STATUS.OK,
                            'ErrorCode':curLongPollingStatus,
                            'ErrorInfo':errorInfo
                        };
                        isNeedCallback && ConnManager.callBack(successInfo);
                        longPollingOn && MsgManager.longPolling();
                    }else{
                        //记录长轮询返回解析json错误次数
                        curLongPollingRetErrorCount++;
                        log.warn("longPolling接口第"+curLongPollingRetErrorCount+"次报错: "+errObj.ErrorInfo);
                        //累计超过一定次数
                        if(curLongPollingRetErrorCount<=LONG_POLLING_MAX_RET_ERROR_COUNT){
                            setTimeout(startNextLongPolling,100);//
                        }else{
                            curLongPollingStatus=CONNECTION_STATUS.OFF;
                            var errInfo={
                                'ActionStatus':ACTION_STATUS.FAIL,
                                'ErrorCode':CONNECTION_STATUS.OFF,
                                'ErrorInfo':'connection is off'
                            };
                            longPollingOffCallbackFlag==false && ConnManager.callBack(errInfo);
                            longPollingOffCallbackFlag=true;
                            log.warn(longPollingIntervalTime+"毫秒之后,SDK会发起新的longPolling请求...");
                            setTimeout(startNextLongPolling,longPollingIntervalTime);//长轮询接口报错次数达到一定值，每间隔5s发起新的长轮询
                        }
                    }
                };
                
                //发起新的长轮询请求
                var startNextLongPolling =function(){
                    longPollingOn && MsgManager.longPolling();
                };
                
                //处理未决的加群申请消息列表
                var handlerApplyJoinGroupSystemMsgs=function(eventArray){
                    for(var i in eventArray){
                            var e=eventArray[i];
                            switch(e.Event){
                                case LONG_POLLINNG_EVENT_TYPE.GROUP_SYSTEM://（多终端同步）群系统消息
                                    log.warn("handlerApplyJoinGroupSystemMsgs： handler new group system msg");
                                    //true 表示 解决加群申请通知存在重复的问题（已处理的通知，下次登录还会拉到），需要判重
                                    handlerGroupSystemMsgs(e.GroupTips,true);
                                    break;
                                default:
                                    log.error("syncMsgs收到未知的群系统消息类型: Event="+e.Event);
                                    break;
                            }
                    }  
                };
                
                //拉取c2c消息(包含加群未决消息，需要处理)
		this.syncMsgs = function(cbOk, cbErr) {
			var notifyInfo = [];
                        var msgInfos=[];
                        //读取C2C消息
			proto_getMsgs(MsgStore.cookie, MsgStore.syncFlag,function(resp) {
				//拉取完毕
                                if(resp.SyncFlag==2){
                                    MsgStore.syncFlag=0;
                                }
                                //处理c2c消息
				msgInfos = resp.MsgList;//返回的消息列表
                                MsgStore.cookie = resp.Cookie;//cookies，记录当前读到的最新消息位置
                                
				for (var i in msgInfos) {
					var msgInfo = msgInfos[i];
					var isSendMsg, id,headUrl;
					if (msgInfo.From_Account == ctx.identifier) {//当前用户发送的消息
						isSendMsg = true;
						id = msgInfo.To_Account;//读取接收者信息
                                                headUrl='';
					} else {//当前用户收到的消息
						isSendMsg = false;
						id = msgInfo.From_Account;//读取发送者信息
                                                headUrl='';
					}
					var sess = MsgStore.sessByTypeId(SESSION_TYPE.C2C, id);
					if (!sess) {	
						sess = new Session(SESSION_TYPE.C2C, id, id, headUrl, 0,0);
					}
					var msg = new Msg(sess, isSendMsg, msgInfo.MsgSeq, msgInfo.MsgRandom,msgInfo.MsgTimeStamp,msgInfo.From_Account);                                       
                                        var msgBody=null;
                                        var msgContent=null;
                                        var msgType=null;
					for (var mi in msgInfo.MsgBody) {
                                                msgBody=msgInfo.MsgBody[mi];
                                                msgType=msgBody.MsgType;
                                                switch(msgType){
                                                    case MSG_ELEMENT_TYPE.TEXT:
                                                        msgContent=new Msg.Elem.Text(msgBody.MsgContent.Text);
                                                        break;
                                                    case MSG_ELEMENT_TYPE.FACE:
                                                         msgContent=new Msg.Elem.Face(
                                                                        msgBody.MsgContent.Index,
                                                                        msgBody.MsgContent.Data
                                                                    );
                                                        break;
                                                    case MSG_ELEMENT_TYPE.IMAGE:
                                                        msgContent=new Msg.Elem.Images(
                                                                        msgBody.MsgContent.UUID
                                                                    );
                                                        for(var j in msgBody.MsgContent.ImageInfoArray){
                                                            var tempImg=msgBody.MsgContent.ImageInfoArray[j];
                                                            msgContent.addImage(
                                                                new Msg.Elem.Images.Image(
                                                                    tempImg.Type,
                                                                    tempImg.Size,
                                                                    tempImg.Width,
                                                                    tempImg.Height,
                                                                    tempImg.URL
                                                                )
                                                            );
                                                        }
                                                        break;
                                                    case MSG_ELEMENT_TYPE.SOUND:
                                                        var soundUrl=getSoundDownUrl(msgBody.MsgContent.UUID,msgInfo.From_Account);
                                                        if(soundUrl){
                                                            msgContent=new Msg.Elem.Sound(
                                                                        msgBody.MsgContent.UUID,
                                                                        msgBody.MsgContent.Second,
                                                                        msgBody.MsgContent.Size,
                                                                        msgInfo.From_Account,
                                                                        soundUrl
                                                                    );
                                                        }else{
                                                            msgType=MSG_ELEMENT_TYPE.TEXT;
                                                            msgContent=new Msg.Elem.Text('[语音消息]下载地址解析出错');
                                                        }
                                                        break;
                                                    case MSG_ELEMENT_TYPE.LOCATION:
                                                        msgType=MSG_ELEMENT_TYPE.TEXT;
                                                        msgContent=new Msg.Elem.Text('web端暂不支持地理位置消息');
                                                        break;
                                                    case MSG_ELEMENT_TYPE.FILE:
                                                    case MSG_ELEMENT_TYPE.FILE+" ":
                                                        msgType=MSG_ELEMENT_TYPE.FILE;
                                                        var fileUrl=getFileDownUrl(msgBody.MsgContent.UUID,msgInfo.From_Account,msgBody.MsgContent.FileName);
                                                        if(fileUrl){
                                                            msgContent=new Msg.Elem.File(
                                                                        msgBody.MsgContent.UUID,
                                                                        msgBody.MsgContent.FileName,
                                                                        msgBody.MsgContent.FileSize,
                                                                        msgInfo.From_Account,
                                                                        fileUrl
                                                                    );
                                                        }else{
                                                            msgType=MSG_ELEMENT_TYPE.TEXT;
                                                            msgContent=new Msg.Elem.Text('[文件消息下载地址解析出错]');
                                                        }
                                                        break;
                                                    case MSG_ELEMENT_TYPE.CUSTOM:
                                                        try{
                                                            var data=JSON.parse(msgBody.MsgContent.Data);
                                                            if(data && data.userAction && data.userAction==FRIEND_WRITE_MSG_ACTION.ING){//过滤安卓或ios的正在输入自定义消息
                                                                continue;
                                                            }
                                                        }catch(e){}
                                                        
                                                        msgType=MSG_ELEMENT_TYPE.CUSTOM;
                                                        msgContent=new Msg.Elem.Custom(
                                                                        msgBody.MsgContent.Data,
                                                                        msgBody.MsgContent.Desc,
                                                                        msgBody.MsgContent.Ext
                                                                    );
                                                        break;
                                                    default :
                                                        msgType=MSG_ELEMENT_TYPE.TEXT;
                                                        msgContent=new Msg.Elem.Text('web端暂不支持'+msgBody.MsgType+'消息');
                                                        break;
                                                }
						msg.elems.push(new Msg.Elem(msgType, msgContent));
					}
                                        
					if (msg.elems.length>0 && MsgStore.addMsg(msg)) {
						notifyInfo.push(msg);
					}
				} // for loop
                                
                                //处理加群未决申请消息
                                handlerApplyJoinGroupSystemMsgs(resp.EventArray);
                                
				if (notifyInfo.length > 0)
					MsgStore.updateTimeline();
				if (cbOk) cbOk(notifyInfo);
				else if (notifyInfo.length > 0) {
					if(onMsgCallback) onMsgCallback(notifyInfo);
				}
				
			}, function(err) {
				log.error("getMsgs failed:" + err.ErrorInfo);
				if (cbErr) cbErr(err);
			});
		};
                
                
                //拉取C2C漫游消息
		this.getC2CHistoryMsgs = function(options,cbOk, cbErr) {
                        
                        if(!options.Peer_Account){
                            if(cbErr){
                                cbErr(tool.getReturnError("Peer_Account is empty",-13));
                                return;
                            }
                        }
                        if(!options.MaxCnt){
                            options.MaxCnt=15;
                        }
                        if(options.MaxCnt<=0){
                            if(cbErr){
                                cbErr(tool.getReturnError("MaxCnt should be greater than 0",-14));
                                return;
                            }
                        }
                        if(options.MaxCnt>15){
                            if(cbErr){
                                cbErr(tool.getReturnError("MaxCnt can not be greater than 15",-15));
                                return;
                            }
                            return;
                        }
                        if(options.MsgKey==null || options.MsgKey==undefined){
                            options.MsgKey='';
                        }
                        var opts={
                          'Peer_Account':  options.Peer_Account,
                          'MaxCnt':  options.MaxCnt,
                          'LastMsgTime':  options.LastMsgTime,
                          'MsgKey':  options.MsgKey
                        };
                        //读取c2c漫游消息
			proto_getC2CHistoryMsgs(opts,function(resp) {
				var msgObjList = [];
				//处理c2c消息
				msgInfos = resp.MsgList;//返回的消息列表
                                //C2CHitoryMsgKeyMap[options.Peer_Account]=resp.MsgKey;
                                
				for (var i in msgInfos) {
					var msgInfo = msgInfos[i];
					var isSendMsg, id,headUrl;
					if (msgInfo.From_Account == ctx.identifier) {//当前用户发送的消息
						isSendMsg = true;
						id = msgInfo.To_Account;//读取接收者信息
                                                headUrl='';
					} else {//当前用户收到的消息
						isSendMsg = false;
						id = msgInfo.From_Account;//读取发送者信息
                                                headUrl='';
					}
					
					var sess = MsgStore.sessByTypeId(SESSION_TYPE.C2C, id);
					if (!sess) {	
						sess = new Session(SESSION_TYPE.C2C, id, id, headUrl, 0,0);
					}
					var msg = new Msg(sess, isSendMsg, msgInfo.MsgSeq, msgInfo.MsgRandom,msgInfo.MsgTimeStamp,msgInfo.From_Account);                                       
                                        var msgBody=null;
                                        var msgContent=null;
                                        var msgType=null;
					for (var mi in msgInfo.MsgBody) {
                                                msgBody=msgInfo.MsgBody[mi];
                                                msgType=msgBody.MsgType;
                                                switch(msgType){
                                                    case MSG_ELEMENT_TYPE.TEXT:
                                                        msgContent=new Msg.Elem.Text(msgBody.MsgContent.Text);
                                                        break;
                                                    case MSG_ELEMENT_TYPE.FACE:
                                                         msgContent=new Msg.Elem.Face(
                                                                        msgBody.MsgContent.Index,
                                                                        msgBody.MsgContent.Data
                                                                    );
                                                        break;
                                                    case MSG_ELEMENT_TYPE.IMAGE:
                                                        msgContent=new Msg.Elem.Images(
                                                                        msgBody.MsgContent.UUID
                                                                    );
                                                        for(var j in msgBody.MsgContent.ImageInfoArray){
                                                            var tempImg=msgBody.MsgContent.ImageInfoArray[j];
                                                            msgContent.addImage(
                                                                new Msg.Elem.Images.Image(
                                                                    tempImg.Type,
                                                                    tempImg.Size,
                                                                    tempImg.Width,
                                                                    tempImg.Height,
                                                                    tempImg.URL
                                                                )
                                                            );
                                                        }
                                                        break;
                                                    case MSG_ELEMENT_TYPE.SOUND:
     
                                                        var soundUrl=getSoundDownUrl(msgBody.MsgContent.UUID,msgInfo.From_Account);
                                                        
                                                        if(soundUrl){
                                                            msgContent=new Msg.Elem.Sound(
                                                                        msgBody.MsgContent.UUID,
                                                                        msgBody.MsgContent.Second,
                                                                        msgBody.MsgContent.Size,
                                                                        msgInfo.From_Account,
                                                                        soundUrl
                                                                    );
                                                        }else{
                                                            msgType=MSG_ELEMENT_TYPE.TEXT;
                                                            msgContent=new Msg.Elem.Text('[语音消息]下载地址解析出错');
                                                        }
                                                        break;
                                                    case MSG_ELEMENT_TYPE.LOCATION:
                                                        msgType=MSG_ELEMENT_TYPE.TEXT;
                                                        msgContent=new Msg.Elem.Text('web端暂不支持地理位置消息');
                                                        break;
                                                    case MSG_ELEMENT_TYPE.FILE:
                                                    case MSG_ELEMENT_TYPE.FILE+" ":
                                                        msgType=MSG_ELEMENT_TYPE.FILE;
                                                        var fileUrl=getFileDownUrl(msgBody.MsgContent.UUID,msgInfo.From_Account,msgBody.MsgContent.FileName);
                                                        
                                                        if(fileUrl){
                                                            msgContent=new Msg.Elem.File(
                                                                        msgBody.MsgContent.UUID,
                                                                        msgBody.MsgContent.FileName,
                                                                        msgBody.MsgContent.FileSize,
                                                                        msgInfo.From_Account,
                                                                        fileUrl
                                                                    );
                                                        }else{
                                                            msgType=MSG_ELEMENT_TYPE.TEXT;
                                                            msgContent=new Msg.Elem.Text('[文件消息下载地址解析出错]');
                                                        }
                                                        break;
                                                    case MSG_ELEMENT_TYPE.CUSTOM:
                                                        msgType=MSG_ELEMENT_TYPE.CUSTOM;
                                                        msgContent=new Msg.Elem.Custom(
                                                                        msgBody.MsgContent.Data,
                                                                        msgBody.MsgContent.Desc,
                                                                        msgBody.MsgContent.Ext
                                                                    );
                                                        
                                                        break;
                                                    default :
                                                        msgType=MSG_ELEMENT_TYPE.TEXT;
                                                        msgContent=new Msg.Elem.Text('web端暂不支持'+msgBody.MsgType+'消息');
                                                        break;
                                                }
						msg.elems.push(new Msg.Elem(msgType, msgContent));
					}
                                        MsgStore.addMsg(msg);
                                        msgObjList.push(msg);
				} // for loop
                                
                                MsgStore.updateTimeline();
				if (cbOk) {
                                    
                                    var newResp={
                                        'Complete':resp.Complete,
                                        'MsgCount':msgObjList.length,
                                        'LastMsgTime':resp.LastMsgTime,
                                        'MsgKey':resp.MsgKey,
                                        'MsgList':msgObjList
                                    };
                                    cbOk(newResp);
                                }
				
			}, function(err) {
				log.error("getC2CHistoryMsgs failed:" + err.ErrorInfo);
				if (cbErr) cbErr(err);
			});
		};
                
                //拉群历史消息
                //不传cbOk 和 cbErr，则会调用新消息回调函数
		this.syncGroupMsgs = function(options,cbOk, cbErr) {
                        if(options.ReqMsgSeq<=0){
                            if(cbErr){
                                var errInfo = "ReqMsgSeq must be greater than 0";
                                var error=tool.getReturnError(errInfo,-16);
                                cbErr(error);
                            }
                            return;
                        }
                        var opts={
                          'GroupId':  options.GroupId,
                          'ReqMsgSeq':  options.ReqMsgSeq,
                          'ReqMsgNumber':  options.ReqMsgNumber
                        };
                        //读群漫游消息
			proto_getGroupMsgs(opts,function(resp) {
				var notifyInfo = [];
				var group_id = resp.GroupId;//返回的群id
				var msgInfos = resp.RspMsgList;//返回的消息列表 
				
                                if(msgInfos==null || msgInfos==undefined){
                                    if(cbOk){
                                        cbOk([]);
                                    }
                                    return;
                                }
				for (var i=msgInfos.length-1;i>=0;i--) {
					var msgInfo = msgInfos[i];
                                        //如果是已经删除的消息或者发送者帐号为空或者消息内容为空
                                        //IsPlaceMsg=1
                                        if(msgInfo.IsPlaceMsg || !msgInfo.From_Account || !msgInfo.MsgBody || msgInfo.MsgBody.length==0){
                                            continue;
                                        }
					var msg=handlerGroupMsg(msgInfo,true,true);
                                        if(msg){
                                            notifyInfo.push(msg);
                                        }
				} // for loop
				if (notifyInfo.length > 0)
					MsgStore.updateTimeline();
				if (cbOk) cbOk(notifyInfo);
				else if (notifyInfo.length > 0) {
					if(onMsgCallback) onMsgCallback(notifyInfo);
				}
				
			}, function(err) {
				log.error("getGroupMsgs failed:" + err.ErrorInfo);
				if (cbErr) cbErr(err);
			});
		};
                
                //处理群消息(普通消息+提示消息)
                //isSyncGroupMsgs 是否主动拉取群消息标志
                //isAddMsgFlag 是否需要保存到MsgStore，如果需要，这里会存在判重逻辑
                var handlerGroupMsg=function (msgInfo,isSyncGroupMsgs,isAddMsgFlag){
                                        if(msgInfo.IsPlaceMsg || !msgInfo.From_Account || !msgInfo.MsgBody || msgInfo.MsgBody.length==0){
                                            return null;
                                        }
                                        var isSendMsg, id,headUrl,fromAccountNick;
                                        var group_id=msgInfo.ToGroupId;
                                        var group_name=group_id;
                                        if(msgInfo.GroupInfo){//取出群名称
                                            if(msgInfo.GroupInfo.GroupName){
                                                group_name=msgInfo.GroupInfo.GroupName;
                                            }
                                        }
                                        //取出成员昵称
                                        fromAccountNick=msgInfo.From_Account;
                                        if(msgInfo.GroupInfo){
                                            if(msgInfo.GroupInfo.From_AccountNick){
                                                fromAccountNick=msgInfo.GroupInfo.From_AccountNick;
                                            }
                                        }
					if (msgInfo.From_Account == ctx.identifier) {//当前用户发送的消息
						isSendMsg = true;
						id = msgInfo.From_Account;//读取接收者信息
                                                headUrl='';
					} else {//当前用户收到的消息
						isSendMsg = false;
						id = msgInfo.From_Account;//读取发送者信息
                                                headUrl='';
					}
					var sess = MsgStore.sessByTypeId(SESSION_TYPE.GROUP, group_id);
					if (!sess) {
						sess = new Session(SESSION_TYPE.GROUP, group_id, group_name, headUrl, 0,0);
					}
                                        var subType=GROUP_MSG_SUB_TYPE.COMMON;//消息类型
                                        //群提示消息,重新封装下
                                        if(LONG_POLLINNG_EVENT_TYPE.GROUP_TIP==msgInfo.Event || LONG_POLLINNG_EVENT_TYPE.GROUP_TIP2==msgInfo.Event){
                                            subType=GROUP_MSG_SUB_TYPE.TIP;
                                            var groupTip=msgInfo.MsgBody;
                                            msgInfo.MsgBody=[];
                                            msgInfo.MsgBody.push({
                                                    "MsgType":MSG_ELEMENT_TYPE.GROUP_TIP,
                                                    "MsgContent":groupTip
                                                }
                                            );
                                        }else if (msgInfo.MsgPriority){//群点赞消息
                                            if(msgInfo.MsgPriority==GROUP_MSG_PRIORITY_TYPE.REDPACKET){
                                                subType=GROUP_MSG_SUB_TYPE.REDPACKET;
                                            }else if(msgInfo.MsgPriority==GROUP_MSG_PRIORITY_TYPE.LOVEMSG){
                                                subType=GROUP_MSG_SUB_TYPE.LOVEMSG;
                                            }
                                            
                                        }
					var msg = new Msg(sess, isSendMsg, msgInfo.MsgSeq, msgInfo.MsgSeq,msgInfo.MsgTimeStamp,msgInfo.From_Account,subType,fromAccountNick);                                       
                                        var msgBody=null;
                                        var msgContent=null;
                                        var msgType=null;
					for (var mi in msgInfo.MsgBody) {
                                                msgBody=msgInfo.MsgBody[mi];
                                                msgType=msgBody.MsgType;
                                                switch(msgType){
                                                    case MSG_ELEMENT_TYPE.TEXT:
                                                        msgContent=new Msg.Elem.Text(msgBody.MsgContent.Text);
                                                        break;
                                                    case MSG_ELEMENT_TYPE.FACE:                                                       
                                                         msgContent=new Msg.Elem.Face(
                                                                        msgBody.MsgContent.Index,
                                                                        msgBody.MsgContent.Data
                                                                    );
                                                        break;
                                                    case MSG_ELEMENT_TYPE.IMAGE:
                                                        msgContent=new Msg.Elem.Images(
                                                                        msgBody.MsgContent.UUID
                                                        );
                                                        for(var j in msgBody.MsgContent.ImageInfoArray){
                                                            msgContent.addImage(
                                                                new Msg.Elem.Images.Image(
                                                                    msgBody.MsgContent.ImageInfoArray[j].Type,
                                                                    msgBody.MsgContent.ImageInfoArray[j].Size,
                                                                    msgBody.MsgContent.ImageInfoArray[j].Width,
                                                                    msgBody.MsgContent.ImageInfoArray[j].Height,
                                                                    msgBody.MsgContent.ImageInfoArray[j].URL
                                                                )
                                                            );
                                                        }
                                                        break;
                                                    case MSG_ELEMENT_TYPE.SOUND:
                                                        var soundUrl=getSoundDownUrl(msgBody.MsgContent.UUID,msgInfo.From_Account);
                                                        if(soundUrl){
                                                            msgContent=new Msg.Elem.Sound(
                                                                        msgBody.MsgContent.UUID,
                                                                        msgBody.MsgContent.Second,
                                                                        msgBody.MsgContent.Size,
                                                                        msgInfo.From_Account,
                                                                        soundUrl
                                                                    );
                                                        }else{
                                                            msgType=MSG_ELEMENT_TYPE.TEXT;
                                                            msgContent=new Msg.Elem.Text('[语音消息]下载地址解析出错');
                                                        }
                                                        break;
                                                    case MSG_ELEMENT_TYPE.LOCATION:
                                                        msgType=MSG_ELEMENT_TYPE.TEXT;
                                                        msgContent=new Msg.Elem.Text('web端暂不支持地理位置消息');
                                                        break;
                                                    case MSG_ELEMENT_TYPE.FILE:
                                                    case MSG_ELEMENT_TYPE.FILE+" ":
                                                        msgType=MSG_ELEMENT_TYPE.FILE;
                                                        var fileUrl=getFileDownUrl(msgBody.MsgContent.UUID,msgInfo.From_Account,msgBody.MsgContent.FileName);
                                                        
                                                        if(fileUrl){
                                                            msgContent=new Msg.Elem.File(
                                                                        msgBody.MsgContent.UUID,
                                                                        msgBody.MsgContent.FileName,
                                                                        msgBody.MsgContent.FileSize,
                                                                        msgInfo.From_Account,
                                                                        fileUrl
                                                                    );
                                                        }else{
                                                            msgType=MSG_ELEMENT_TYPE.TEXT;
                                                            msgContent=new Msg.Elem.Text('[文件消息]地址解析出错');
                                                        }
                                                        break;
                                                    case MSG_ELEMENT_TYPE.GROUP_TIP:
                                                        var opType=msgBody.MsgContent.OpType;
                                                        msgContent=new Msg.Elem.GroupTip(
                                                                        opType,
                                                                        msgBody.MsgContent.Operator_Account,
                                                                        group_id,
                                                                        msgInfo.GroupInfo.GroupName,
                                                                        msgBody.MsgContent.List_Account
                                                                    );
                                                        if(GROUP_TIP_TYPE.JOIN==opType || GROUP_TIP_TYPE.QUIT==opType){//加群或退群时，设置最新群成员数
                                                            msgContent.setGroupMemberNum(msgBody.MsgContent.MemberNum);
                                                        }else if(GROUP_TIP_TYPE.MODIFY_GROUP_INFO==opType){//群资料变更
                                                            var tempIsCallbackFlag=false;
                                                            var tempNewGroupInfo={
                                                                "GroupId":group_id,
                                                                "GroupFaceUrl":null,
                                                                "GroupName":null,
                                                                "OwnerAccount":null,
                                                                "GroupNotification":null,
                                                                "GroupIntroduction":null
                                                            };
                                                            var msgGroupNewInfo=msgBody.MsgContent.MsgGroupNewInfo;
                                                            if(msgGroupNewInfo.GroupFaceUrl){
                                                                var tmpNGIFaceUrl=new Msg.Elem.GroupTip.GroupInfo(
                                                                                    GROUP_TIP_MODIFY_GROUP_INFO_TYPE.FACE_URL,
                                                                                    msgGroupNewInfo.GroupFaceUrl
                                                                                );
                                                                msgContent.addGroupInfo(tmpNGIFaceUrl);
                                                                tempIsCallbackFlag=true;
                                                                tempNewGroupInfo.GroupFaceUrl=msgGroupNewInfo.GroupFaceUrl;
                                                            }
                                                            if(msgGroupNewInfo.GroupName){
                                                                var tmpNGIName=new Msg.Elem.GroupTip.GroupInfo(
                                                                                    GROUP_TIP_MODIFY_GROUP_INFO_TYPE.NAME,
                                                                                    msgGroupNewInfo.GroupName
                                                                                );
                                                                msgContent.addGroupInfo(tmpNGIName);
                                                                tempIsCallbackFlag=true;
                                                                tempNewGroupInfo.GroupName=msgGroupNewInfo.GroupName;
                                                            }
                                                            if(msgGroupNewInfo.Owner_Account){
                                                                var tmpNGIOwner=new Msg.Elem.GroupTip.GroupInfo(
                                                                                    GROUP_TIP_MODIFY_GROUP_INFO_TYPE.OWNER,
                                                                                    msgGroupNewInfo.Owner_Account
                                                                                );
                                                                msgContent.addGroupInfo(tmpNGIOwner);
                                                                tempIsCallbackFlag=true;
                                                                tempNewGroupInfo.OwnerAccount=msgGroupNewInfo.Owner_Account;
                                                            }
                                                            if(msgGroupNewInfo.GroupNotification){
                                                                var tmpNGINotification=new Msg.Elem.GroupTip.GroupInfo(
                                                                                    GROUP_TIP_MODIFY_GROUP_INFO_TYPE.NOTIFICATION,
                                                                                    msgGroupNewInfo.GroupNotification
                                                                                );
                                                                msgContent.addGroupInfo(tmpNGINotification);
                                                                tempIsCallbackFlag=true;
                                                                tempNewGroupInfo.GroupNotification=msgGroupNewInfo.GroupNotification;
                                                            }
                                                            if(msgGroupNewInfo.GroupIntroduction){
                                                                var tmpNGIIntroduction=new Msg.Elem.GroupTip.GroupInfo(
                                                                                    GROUP_TIP_MODIFY_GROUP_INFO_TYPE.INTRODUCTION,
                                                                                    msgGroupNewInfo.GroupIntroduction
                                                                                );
                                                                msgContent.addGroupInfo(tmpNGIIntroduction);
                                                                tempIsCallbackFlag=true;
                                                                tempNewGroupInfo.GroupIntroduction=msgGroupNewInfo.GroupIntroduction;
                                                            }
                                                            
                                                            //回调群资料变化通知方法
                                                            if(isSyncGroupMsgs==false && tempIsCallbackFlag && onGroupInfoChangeCallback){
                                                                onGroupInfoChangeCallback(tempNewGroupInfo);
                                                            }
                                                            
                                                        }else if(GROUP_TIP_TYPE.MODIFY_MEMBER_INFO==opType){//群成员变更
                                                            var memberInfos=msgBody.MsgContent.MsgMemberInfo;
                                                            for(var n in memberInfos){
                                                                var memberInfo=memberInfos[n];
                                                                msgContent.addMemberInfo(
                                                                        new Msg.Elem.GroupTip.MemberInfo(
                                                                            memberInfo.User_Account,memberInfo.ShutupTime
                                                                        )
                                                                );
                                                            }
                                                        }
                                                        break;
                                                    case MSG_ELEMENT_TYPE.CUSTOM:
                                                        msgType=MSG_ELEMENT_TYPE.CUSTOM;
                                                        msgContent=new Msg.Elem.Custom(
                                                                        msgBody.MsgContent.Data,
                                                                        msgBody.MsgContent.Desc,
                                                                        msgBody.MsgContent.Ext
                                                                    );
                                                        break;
                                                    default :
                                                        msgType=MSG_ELEMENT_TYPE.TEXT;
                                                        msgContent=new Msg.Elem.Text('web端暂不支持'+msgBody.MsgType+'消息');
                                                        break;
                                                }
						msg.elems.push(new Msg.Elem(msgType, msgContent));
					}
                                        
                                        if(isAddMsgFlag==false){//不需要保存消息
                                            return msg;
                                        }
                                        
					if (MsgStore.addMsg(msg)) {
                                                //更新我的群最大的消息seq
                                                var tempCurMaxSeq=myGroupMaxSeqs[group_id];
                                                if(tempCurMaxSeq){
                                                    if(msgInfo.MsgSeq>tempCurMaxSeq){
                                                        myGroupMaxSeqs[group_id]=msgInfo.MsgSeq;
                                                    }
                                                }else{
                                                    myGroupMaxSeqs[group_id]=msgInfo.MsgSeq;
                                                }
                                                return msg;
					}else{
                                            return null;
                                        }
                };
                
                //初始化
		this.init = function(listeners,cbOk,cbErr) {
                        if(!listeners.onMsgNotify){
                            log.warn('listeners.onMsgNotify is empty');
                        }
			onMsgCallback = listeners.onMsgNotify;
                        
                        if(listeners.onBigGroupMsgNotify){
                            onBigGroupMsgCallback = listeners.onBigGroupMsgNotify;
                        }else{
                            log.warn('listeners.onBigGroupMsgNotify is empty');
                        }
                        
                        if(listeners.onGroupSystemNotifys){
                            onGroupSystemNotifyCallbacks=listeners.onGroupSystemNotifys;
                        }else{
                            log.warn('listeners.onGroupSystemNotifys is empty');
                        }
                        if(listeners.onGroupInfoChangeNotify){
                            onGroupInfoChangeCallback=listeners.onGroupInfoChangeNotify;
                        }else{
                            log.warn('listeners.onGroupInfoChangeNotify is empty');
                        }
                        if(listeners.onFriendSystemNotifys){
                            onFriendSystemNotifyCallbacks=listeners.onFriendSystemNotifys;
                        }else{
                            log.warn('listeners.onFriendSystemNotifys is empty');
                        }
                        if(listeners.onProfileSystemNotifys){
                            onProfileSystemNotifyCallbacks=listeners.onProfileSystemNotifys;
                        }else{
                            log.warn('listeners.onProfileSystemNotifys is empty');
                        }
                        
                        if(!ctx.identifier || !ctx.userSig){
                            if(cbOk){
                                var success={
                                    'ActionStatus':ACTION_STATUS.OK,
                                    'ErrorCode':0,
                                    'ErrorInfo':"login success(no login state)"
                                };
                                cbOk(success);
                            }
                            return;
                        }
                        
                        //初始化
                        initMyGroupMaxSeqs(
                                function(resp){
                                    log.info('initMyGroupMaxSeqs success');
                                    //初始化文件
                                    initIpAndAuthkey(
                                            function(initIpAndAuthkeyResp){
                                                log.info('initIpAndAuthkey success');
                                                if(cbOk){
                                                    log.info('login success(have login state))');
                                                    var success={
                                                        'ActionStatus':ACTION_STATUS.OK,
                                                        'ErrorCode':0,
                                                        'ErrorInfo':"login success"
                                                    };
                                                    cbOk(success);
                                                }
                                                MsgManager.setLongPollingOn(true);//开启长轮询
                                                longPollingOn && MsgManager.longPolling(cbOk);
                                            },cbErr);
                                },cbErr);
		};

                //发消息（私聊或群聊）
		this.sendMsg = function(msg, cbOk, cbErr) {
			proto_sendMsg(msg, function(resp) {
                                //私聊时，加入自己的发的消息，群聊时，由于seq和服务器的seq不一样，所以不作处理
                                if(msg.sess.type()==SESSION_TYPE.C2C){
                                    if (!MsgStore.addMsg(msg)) {                                   
					var errInfo = "sendMsg: addMsg failed!";
                                        var error=tool.getReturnError(errInfo,-17);
					log.error(errInfo);
					if (cbErr) cbErr(error);
					return;
                                    }
                                    //更新信息流时间
                                    MsgStore.updateTimeline();
                                }
				if (cbOk) cbOk(resp);
			}, function(err) {
				if (cbErr) cbErr(err);
			});
		};
                
                //获取语音下载url
                var getSoundDownUrl=function(uuid,senderId){
                    var soundUrl=null;
                    if(authkey && ipList[0]){
                        soundUrl="http://"+ipList[0]+"/asn.com/stddownload_common_file?authkey="+authkey+"&bid="+DOWNLOAD_FILE.BUSSINESS_ID+"&subbid="+ctx.sdkAppID+"&fileid="+uuid+"&filetype="+DOWNLOAD_FILE_TYPE.SOUND+"&openid="+senderId+"&ver=0";
                    }else{
                        log.error("拼接语音下载url不报错：ip或者authkey为空");
                    }
                    return soundUrl;
                };
                
                //获取文件下载地址
                var getFileDownUrl=function(uuid,senderId,fileName){
                    var fileUrl=null;
                    if(authkey && ipList[0]){
                        fileUrl="http://"+ipList[0]+"/asn.com/stddownload_common_file?authkey="+authkey+"&bid="+DOWNLOAD_FILE.BUSSINESS_ID+"&subbid="+ctx.sdkAppID+"&fileid="+uuid+"&filetype="+DOWNLOAD_FILE_TYPE.FILE+"&openid="+senderId+"&ver=0&filename="+encodeURIComponent(fileName);
                    }else{
                        log.error("拼接文件下载url不报错：ip或者authkey为空");
                    }
                    return fileUrl;
                };
	};
        
        //上传文件
        var FileUploder=new function() {
                this.fileMd5=null;
                //获取文件MD5
                var getFileMD5=function(file,cbOk,cbErr){
                    
                    //FileReader pc浏览器兼容性
                    //Feature	Firefox (Gecko)	Chrome	Internet Explorer	Opera	Safari
                    //Basic support	3.6	7	10                      12.02	6.0.2
                    var fileReader=null;
                    try{
                        fileReader = new FileReader();//分块读取文件对象
                    }catch(e){
                        if(cbErr){
                            cbErr(tool.getReturnError('当前浏览器不支持FileReader',-18));
                            return;
                        }
                    }
                    //file的slice方法，注意它的兼容性，在不同浏览器的写法不同
                    var blobSlice = File.prototype.mozSlice || File.prototype.webkitSlice || File.prototype.slice;
                    if(!blobSlice){
                        if(cbErr){
                            cbErr(tool.getReturnError('当前浏览器不支持FileAPI',-19));
                            return;
                        }
                    }
                    
                    var chunkSize = 2 * 1024 * 1024;//分块大小，2M
                    var chunks = Math.ceil(file.size / chunkSize);//总块数
                    var currentChunk = 0;//当前块数
                    var spark = new SparkMD5();//获取MD5对象
                    
                    fileReader.onload = function (e) {//数据加载完毕事件
                        
                        var binaryStr = "";
                        var bytes = new Uint8Array(e.target.result);
                        var length = bytes.byteLength;
                        for (var i = 0; i < length; i++) 
                        {
                            binaryStr += String.fromCharCode(bytes[i]);//二进制转换字符串
                        }
                        spark.appendBinary(binaryStr);
                        currentChunk++;
                        if (currentChunk < chunks) {
                            loadNext();//读取下一块数据
                        } else {
                            this.fileMd5 = spark.end();//得到文件MD5值
                            if(cbOk){
                                cbOk(this.fileMd5);
                            }
                        }
                    };
                    //分片读取文件
                    function loadNext() {
                        var start = currentChunk * chunkSize, end = start + chunkSize >= file.size ? file.size : start + chunkSize;
                        //根据开始和结束位置，切割文件
                        var b=blobSlice.call(file, start, end);
                        //readAsBinaryString ie浏览器不兼容此方法
                        //fileReader.readAsBinaryString(blobSlice.call(file, start, end));
                        fileReader.readAsArrayBuffer(b);//ie，chrome，firefox等主流浏览器兼容此方法
                        
                    }
                    loadNext();//开始读取
                }; 
                //提交上传图片表单(用于低版本IE9以下)
                this.submitUploadFileForm=function(options,cbOk, cbErr){
                    var errInfo;
                    var error;
                    var formId=options.formId;
                    var fileId=options.fileId;
                    var iframeNum = uploadResultIframeId++;
                    var iframeName="uploadResultIframe_"+iframeNum;
                    var toAccount=options.To_Account;
                    var businessType=options.businessType;
                    
                    var form=document.getElementById(formId);
                    if(!form){
                        errInfo = "获取表单对象为空: formId="+formId+"(formId非法)";
                        error=tool.getReturnError(errInfo,-20);
                        if (cbErr) cbErr(error);
                        return;
                    }
                    
                    var fileObj=document.getElementById(fileId);
                    if(!fileObj){
                        errInfo = "获取文件对象为空: fileId="+fileId+"(没有选择文件或者fileId非法)";
                        error=tool.getReturnError(errInfo,-21);
                        if (cbErr) cbErr(error);
                        return;
                    }
                    //fileObj.type="file";//ie8下不起作用，必须由业务自己设置
                    fileObj.name="file";
                    
                    var iframe = document.createElement("iframe");
                    iframe.name =iframeName;
                    iframe.id = iframeName;
                    iframe.style.display="none";
                    document.body.appendChild(iframe);
                    
                    var cmdName;
                    if(isAccessFormalEnv()){
                        cmdName='pic_up';
                    }else{
                        cmdName='pic_up_test';
                    }
                    var uploadApiUrl="https://pic.tim.qq.com/v4/openpic/"+cmdName+"?tinyid="+ctx.tinyid+"&a2="+ctx.a2+"&sdkappid="+ctx.sdkAppID+"&accounttype="+ctx.accountType+"&contenttype=http";
                    form.action=uploadApiUrl;
                    form.method='post';
                    //form.enctype='multipart/form-data';//ie8下不起作用，必须由业务自己设置
                    form.target=iframeName;
                    
                    function createFormInput(name,value){
                        var tempInput=document.createElement("input");
                        tempInput.type = "hidden";
                        tempInput.name = name;
                        tempInput.value =value;
                        form.appendChild(tempInput);
                    }
                    
                    createFormInput("App_Version",SDK.APPID.toString());
                    createFormInput("From_Account",ctx.identifier);
                    createFormInput("To_Account",toAccount);
                    createFormInput("Seq",nextSeq().toString());
                    createFormInput("Timestamp",unixtime().toString());
                    createFormInput("Random",createRandom().toString());
                    createFormInput("Busi_Id",businessType);
                    createFormInput("PkgFlag","0");
                    

                    //检测iframe.contentWindow.name是否有值
                    function checkFrameName() {
                        var resp;
                        try {
                            resp = JSON.parse(iframe.contentWindow.name) || {};
                        }catch (e) {
                            resp={};
                        }
                        if (resp.ActionStatus) {//上传接口返回
                            // We've got what we need. Stop the iframe from loading further content.
                            iframe.src = "about:blank";
                            iframe.parentNode.removeChild(iframe);
                            iframe = null;
                            
                            if(resp.ActionStatus==ACTION_STATUS.OK){  
                                cbOk && cbOk(resp);
                            }else{
                                cbErr && cbErr(resp);
                            }
                        }else{
                            setTimeout(checkFrameName, 100);
                        }
                    }
                    setTimeout(checkFrameName, 500);
                    
                    form.submit();//提交上传图片表单
                };
                //上传图片(用于高版本浏览器，支持FileAPI)
                this.uploadFile=function(options,cbOk, cbErr){
                    
                    var file_upload = {
                        //初始化
                        init: function (options,cbOk, cbErr) {
                            var me = this;
                            me.file = options.file;
                            //分片上传进度回调事件
                            me.onProgressCallBack=options.onProgressCallBack;
                            //停止上传图片按钮
                            if(options.abortButton){
                                options.abortButton.onclick = me.abortHandler;
                            }
                            me.total =me.file.size;//图片总大小
                            me.loaded = 0;//已读取字节数
                            me.step = 120 * 1024;//分块大小，120K
                            me.sliceSize = 0;//分片大小
                            me.sliceOffset = 0;//当前分片位置
                            me.timestamp = unixtime();//当前时间戳
                            me.seq=nextSeq();//请求seq
                            me.random=createRandom();//请求随机数
                            me.fromAccount=ctx.identifier;//发送者
                            me.toAccount=options.To_Account;//接收者
                            me.fileMd5=options.fileMd5;//文件MD5
                            me.businessType=options.businessType;//图片业务类型，群消息:1; c2c消息:2; 个人头像：3; 群头像：4;
                            
                            me.cbOk=cbOk;//上传成功回调事件
                            me.cbErr=cbErr;//上传失败回调事件
                            
                            me.reader = new FileReader();//读取文件对象
                            me.blobSlice = File.prototype.mozSlice || File.prototype.webkitSlice || File.prototype.slice;//file的slice方法,不同浏览器不一样

                            me.reader.onloadstart = me.onLoadStart;//开始读取回调事件
                            me.reader.onprogress = me.onProgress;//读取文件进度回调事件
                            me.reader.onabort = me.onAbort;//停止读取回调事件
                            me.reader.onerror = me.onerror;//读取发生错误回调事件
                            me.reader.onload = me.onLoad;//分片加载完毕回调事件
                            me.reader.onloadend = me.onLoadEnd;//读取文件完毕回调事件
                    },
                    //上传方法
                    upload: function () {
                        var me = file_upload;
                        //读取第一块
                        me.readBlob(0);
                    },
                    onLoadStart: function () {
                        var me = file_upload;
                    },
                    onProgress: function (e) {
                        var me = file_upload;
                        me.loaded += e.loaded;
                        if(me.onProgressCallBack){
                            me.onProgressCallBack(me.loaded,me.total);
                        }
                    },
                    onAbort: function () {
                        var me = file_upload;
                    },
                    onError: function () {
                        var me = file_upload;
                    },
                    onLoad: function (e) {
                        var me = file_upload;
                        if (e.target.readyState == FileReader.DONE) {
                            var slice_data_base64 = e.target.result;
                            //注意，一定要去除base64编码头部
                            var pos=slice_data_base64.indexOf(",");
                            if(pos!=-1){
                                slice_data_base64=slice_data_base64.substr(pos+1);
                            }
                            //封装上传图片接口的请求参数
                            var opt = {
                                'From_Account': me.fromAccount,
                                'To_Account': me.toAccount,
                                'Busi_Id': me.businessType,
                                'File_Str_Md5': me.fileMd5,
                                'PkgFlag': 1,
                                'File_Size': me.total,
                                'Slice_Offset': me.sliceOffset,
                                'Slice_Size': me.sliceSize,
                                'Slice_Data': slice_data_base64,
                                'Seq': me.seq,
                                'Timestamp': me.timestamp,
                                'Random': me.random
                            };
                            //分片上传图片接口
                            proto_uploadPic(opt,
                                function (resp) {
                                    if (resp.IsFinish == 0) {
                                        me.loaded=resp.Next_Offset;
                                        if (me.loaded < me.total) {
                                            me.readBlob(me.loaded);
                                        } else {
                                            me.loaded = me.total;
                                        }
                                    } else {
                                        
                                        if(me.cbOk){
                                            var tempResp={
                                                'ActionStatus':resp.ActionStatus,
                                                'ErrorCode':resp.ErrorCode,
                                                'ErrorInfo':resp.ErrorInfo,
                                                'File_UUID':resp.File_UUID,
                                                'URL_INFO':resp.URL_INFO
                                            };
                                            me.cbOk(tempResp); 
                                        }
                                    }
                                },
                                me.cbErr
                            );
                        }
                    },
                    onLoadEnd: function () {
                        var me = file_upload;
                    },
                    //分片读取文件方法
                    readBlob: function (start) {
                        var me = file_upload;
                        var blob, file = me.file;
                        var end = start + me.step;
                        if (end > me.total) {
                            end = me.total;
                            me.sliceSize = end - start;
                        } else {
                            me.sliceSize = me.step;
                        }
                        me.sliceOffset=start;
                        //根据起始和结束位置，分片读取文件
                        blob = me.blobSlice.call(file, start, end);
                        //将分片的二进制数据转换为base64编码
                        me.reader.readAsDataURL(blob);
                    },
                    abortHandler: function () {
                        var me = file_upload;
                        if (me.reader) {
                            me.reader.abort();
                        }
                    }
                };
                
                //读取文件MD5
                getFileMD5(options.file,
                               function(fileMd5){
                                    log.info('fileMd5: '+fileMd5);
                                    options.fileMd5=fileMd5;
                                    //初始化上传参数
                                    file_upload.init(options,cbOk, cbErr);
                                    //开始上传文件
                                    file_upload.upload();
                               },
                               cbErr
                );
            };
        };

	
        
        //web im 基础对象
        
        //常量对象
        
        //会话类型
        webim.SESSION_TYPE=SESSION_TYPE;
        
        webim.MSG_MAX_LENGTH=MSG_MAX_LENGTH;
        
        //c2c消息子类型
        webim.C2C_MSG_SUB_TYPE=C2C_MSG_SUB_TYPE;
        
        //群消息子类型
        webim.GROUP_MSG_SUB_TYPE=GROUP_MSG_SUB_TYPE;
        
        //消息元素类型
        webim.MSG_ELEMENT_TYPE=MSG_ELEMENT_TYPE;
        
        //群提示消息类型
        webim.GROUP_TIP_TYPE=GROUP_TIP_TYPE;
        
        //图片类型
        webim.IMAGE_TYPE=IMAGE_TYPE;
        
        //群系统消息类型
        webim.GROUP_SYSTEM_TYPE=GROUP_SYSTEM_TYPE;
        
        //好友系统通知子类型
        webim.FRIEND_NOTICE_TYPE=FRIEND_NOTICE_TYPE;
        
        //群提示消息-群资料变更类型
        webim.GROUP_TIP_MODIFY_GROUP_INFO_TYPE=GROUP_TIP_MODIFY_GROUP_INFO_TYPE;
        
        //浏览器信息
        webim.BROWSER_INFO=BROWSER_INFO;
        
        //表情对象
	webim.Emotions=webim.EmotionPicData= emotions;
        //表情标识符和index Map
	webim.EmotionDataIndexs=webim.EmotionPicDataIndex= emotionDataIndexs;
        
        //腾讯登录服务错误码(托管模式)
        webim.TLS_ERROR_CODE=TLS_ERROR_CODE;
        
        //连接状态
        webim.CONNECTION_STATUS=CONNECTION_STATUS;
        
        //上传图片业务类型
        webim.UPLOAD_PIC_BUSSINESS_TYPE=UPLOAD_PIC_BUSSINESS_TYPE;
        
        
        /**************************************/
        
        //类对象
        //
        //工具对象
        webim.Tool = tool;
        //控制台打印日志对象
        webim.Log= log;
        
        //消息对象
        webim.Msg = Msg;
        //会话对象
	webim.Session = Session;
        //会话存储对象
	webim.MsgStore = {
		sessMap: function() {return MsgStore.sessMap();},
		sessCount: function() {return MsgStore.sessCount();},
		sessByTypeId: function(type, id) {return MsgStore.sessByTypeId(type, id);},
		delSessByTypeId: function(type, id) {return MsgStore.delSessByTypeId(type, id);},
		resetCookieAndSyncFlag: function() {return MsgStore.resetCookieAndSyncFlag();}
	};
        
        /**************************************/
        
        // webim API impl
        // 
        //基本接口
        //登录
	webim.login=webim.init=function(loginInfo, listeners,opts,cbOk,cbErr) {
                
                //初始化连接状态回调函数
                ConnManager.init(listeners.onConnNotify,cbOk,cbErr);
                
                //设置ie9以下浏览器jsonp回调
                if(listeners.jsonpCallback) jsonpCallback=listeners.jsonpCallback;
                //登录
                _login(loginInfo,listeners,opts,cbOk,cbErr);
	};
        //登出
        webim.logout=webim.offline = function(cbOk, cbErr) {return proto_logout(cbOk, cbErr);};
        
        
        //消息管理接口
        //发消息接口（私聊和群聊）
        webim.sendMsg = function(msg, cbOk, cbErr) {return MsgManager.sendMsg(msg, cbOk, cbErr);};
        //拉取未读c2c消息
	webim.syncMsgs = function(cbOk, cbErr) {return MsgManager.syncMsgs(cbOk, cbErr);};
        //拉取C2C漫游消息
	webim.getC2CHistoryMsgs = function(options,cbOk, cbErr) {return MsgManager.getC2CHistoryMsgs(options,cbOk, cbErr);};
        //拉取群漫游消息
	webim.syncGroupMsgs = function(options,cbOk, cbErr) {return MsgManager.syncGroupMsgs(options,cbOk, cbErr);};
        
        //上报c2c消息已读
        webim.c2CMsgReaded = function(options,cbOk,cbErr) {return MsgStore.c2CMsgReaded(options,cbOk,cbErr);};
        
        //上报群消息已读
        webim.groupMsgReaded = function(options,cbOk,cbErr) {return proto_groupMsgReaded(options,cbOk,cbErr);};
        
        //设置聊天会话自动标记已读
        webim.setAutoRead = function(selSess,isOn,isResetAll) {return MsgStore.setAutoRead(selSess, isOn, isResetAll);};
	
        //群组管理接口
        //
        //创建群
        webim.createGroup = function(options,cbOk, cbErr) {return proto_createGroup(options,cbOk, cbErr);};
        //创建群-高级接口
        webim.createGroupHigh = function(options,cbOk, cbErr) {return proto_createGroupHigh(options,cbOk, cbErr);};
        //申请加群
        webim.applyJoinGroup = function(options,cbOk, cbErr) {return proto_applyJoinGroup(options,cbOk, cbErr);};
        //处理加群申请(同意或拒绝)
        webim.handleApplyJoinGroupPendency = function(options,cbOk, cbErr) {return proto_handleApplyJoinGroupPendency(options,cbOk, cbErr);};
        
        //删除加群申请
        webim.deleteApplyJoinGroupPendency= function(options,cbOk,cbErr) {return proto_deleteC2CMsg(options,cbOk,cbErr);};
        
        //主动退群
        webim.quitGroup = function(options,cbOk, cbErr) {return proto_quitGroup(options,cbOk, cbErr);};
        //获取群组公开资料-用于搜索群
        webim.getGroupPublicInfo = function(options,cbOk, cbErr) {return proto_getGroupPublicInfo(options,cbOk, cbErr);};
        //获取群组详细资料-高级接口
        webim.getGroupInfo = function(options,cbOk, cbErr) {return proto_getGroupInfo(options,cbOk, cbErr);};
        //修改群基本资料
        webim.modifyGroupBaseInfo = function(options,cbOk, cbErr) {return proto_modifyGroupBaseInfo(options,cbOk, cbErr);};
        //获取群成员列表
        webim.getGroupMemberInfo = function(options,cbOk, cbErr) {return proto_getGroupMemberInfo(options,cbOk, cbErr);};
        //邀请好友加群
        webim.addGroupMember = function(options,cbOk, cbErr) {return proto_addGroupMember(options,cbOk, cbErr);};
        //修改群成员资料
        webim.modifyGroupMember = function(options,cbOk, cbErr) {return proto_modifyGroupMember(options,cbOk, cbErr);};
        //删除群成员
        webim.deleteGroupMember = function(options,cbOk, cbErr) {return proto_deleteGroupMember(options,cbOk, cbErr);};
        //解散群
        webim.destroyGroup = function(options,cbOk, cbErr) {return proto_destroyGroup(options,cbOk, cbErr);};
        
        //获取我的群组列表-高级接口
        webim.getJoinedGroupListHigh = function(options,cbOk, cbErr) {return proto_getJoinedGroupListHigh(options,cbOk, cbErr);};
        //获取群成员角色
        webim.getRoleInGroup = function(options,cbOk, cbErr) {return proto_getRoleInGroup(options,cbOk, cbErr);};
        //设置群成员禁言时间
        webim.forbidSendMsg = function(options,cbOk, cbErr) {return proto_forbidSendMsg(options,cbOk, cbErr);};
        //发送自定义群系统通知
        webim.sendCustomGroupNotify = function(options,cbOk, cbErr) {return proto_sendCustomGroupNotify(options,cbOk, cbErr);};
        
        //进入大群
        webim.applyJoinBigGroup = function(options,cbOk, cbErr) {return proto_applyJoinBigGroup(options,cbOk, cbErr);};
        //退出大群
        webim.quitBigGroup = function(options,cbOk, cbErr) {return proto_quitBigGroup(options,cbOk, cbErr);};
        
        //资料关系链管理接口
        //
        //获取个人资料接口，可用于搜索用户
        webim.getProfilePortrait = function(options,cbOk, cbErr) {return proto_getProfilePortrait(options,cbOk, cbErr);};
        //设置个人资料
        webim.setProfilePortrait = function(options,cbOk, cbErr) {return proto_setProfilePortrait(options,cbOk, cbErr);};
        //申请加好友
        webim.applyAddFriend = function(options,cbOk, cbErr) {return proto_applyAddFriend(options,cbOk, cbErr);};
        //获取好友申请列表
        webim.getPendency = function(options,cbOk, cbErr) {return proto_getPendency(options,cbOk, cbErr);};
        //删除好友申请
        webim.deletePendency = function(options,cbOk, cbErr) {return proto_deletePendency(options,cbOk, cbErr);};
        //处理好友申请
        webim.responseFriend = function(options,cbOk, cbErr) {return proto_responseFriend(options,cbOk, cbErr);};
        //获取我的好友
        webim.getAllFriend = function(options,cbOk, cbErr) {return proto_getAllFriend(options,cbOk, cbErr);};
        //删除好友
        webim.deleteFriend = function(options,cbOk, cbErr) {return proto_deleteFriend(options,cbOk, cbErr);};
        //拉黑
        webim.addBlackList = function(options,cbOk, cbErr) {return proto_addBlackList(options,cbOk, cbErr);};
        //删除黑名单
        webim.deleteBlackList = function(options,cbOk, cbErr) {return proto_deleteBlackList(options,cbOk, cbErr);};
        //获取我的黑名单
        webim.getBlackList = function(options,cbOk, cbErr) {return proto_getBlackList(options,cbOk, cbErr);};
        
        //图片服务接口
        //
        //上传图片接口（高版本浏览器）
        webim.uploadPic = function(options,cbOk, cbErr) {
            return FileUploder.uploadFile(options,cbOk, cbErr);
        };
        //提交上传图片表单接口（用于低版本ie）
        webim.submitUploadFileForm = function(options,cbOk, cbErr) {
            return FileUploder.submitUploadFileForm(options,cbOk, cbErr);
        };
        
        //设置jsonp返回的值
        webim.setJsonpLastRspData=function(rspData){
            jsonpLastRspData=typeof (rspData) == "string" ? JSON.parse(rspData) : rspData;
        };
        
})(webim);